# 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 #endif
    00025
    00026 #if QT_VERSION >= 0x040300
    00027 /*
    00028   With Qt >= 4.3 drawing of the tracker can be implemented in an
    00029   easier, using the textRect as mask. Because calculating
    00030   a QRegion from a QBitmask is expensive operation ( especially for
    00031   longer texts !) this implementation is much faster too.
    00032   Also the result looks much better.
    00033 */
    00034 #define USE_TRACKER_RECT_MASK
    00035 #endif
    00036
    00037 #ifndef USE_TRACKER_RECT_MASK
    00038 #define USE_TRACKER_BACKGROUND
    00039 #endif
    00040
    00041 class QwtPicker::PrivateData
    00042 {
    00043 public:
    00044     class PickerWidget: public QWidget
    00045     {
    00046     public:
    00047         enum Type
    00048         {
    00049             RubberBand,
    00050             Text
    00051         };
    00052         PickerWidget(QwtPicker *, QWidget *, Type);
    00053         virtual void updateMask();
    00054
    00055 #ifdef USE_TRACKER_BACKGROUND
    00056         /*
    00057            Internal flag, that is needed for tracker texts with a
    00058            background. This flag has been introduced in Qwt 5.0.2 to avoid
    00059            incompatible API changes. In Qwt 5.1 will be a cleaner solution.
    00060          */
    00061         mutable bool d_hasTrackerBackground;
    00062 #endif
    00063     protected:
    00064         virtual void paintEvent(QPaintEvent *);
    00065
    00066         QwtPicker *d_picker;
    00067         Type d_type;
    00068     };
    00069
    00070     bool enabled;
    00071
    00072     QwtPickerMachine *stateMachine;
    00073
    00074     int selectionFlags;
    00075     QwtPicker::ResizeMode resizeMode;
    00076
    00077     QwtPicker::RubberBand rubberBand;
    00078     QPen rubberBandPen;
    00079
    00080     QwtPicker::DisplayMode trackerMode;
    00081     QPen trackerPen;
    00082     QFont trackerFont;
    00083
    00084     QwtPolygon selection;
    00085     bool isActive;
    00086     QPoint labelPosition;
    00087
    00088     bool mouseTracking; // used to save previous value
    00089
    00090     /*
    00091       On X11 the widget below the picker widgets gets paint events
    00092       with a region that is the bounding rect of the mask, if it is complex.
    00093       In case of (f.e) a CrossRubberBand and a text this creates complete
    00094       repaints of the widget. So we better use two different widgets.
    00095      */
    00096
    00097 #if QT_VERSION < 0x040000
    00098     QGuardedPtr<PickerWidget> rubberBandWidget;
    00099     QGuardedPtr<PickerWidget> trackerWidget;
    00100 #else
    00101     QPointer<PickerWidget> rubberBandWidget;
    00102     QPointer<PickerWidget> trackerWidget;
    00103 #endif
    00104 };
    00105
    00106 QwtPicker::PrivateData::PickerWidget::PickerWidget(
    00107         QwtPicker *picker, QWidget *parent, Type type):
    00108     QWidget(parent),
    00109     d_picker(picker),
    00110     d_type(type)
    00111 {
    00112 #if QT_VERSION >= 0x040000
    00113     setAttribute(Qt::WA_TransparentForMouseEvents);
    00114     setAttribute(Qt::WA_NoSystemBackground);
    00115     setFocusPolicy(Qt::NoFocus);
    00116 #else
    00117     setBackgroundMode(Qt::NoBackground);
    00118     setFocusPolicy(QWidget::NoFocus);
    00119     setMouseTracking(true);
    00120 #endif
    00121     hide();
    00122 }
    00123
    00124 void QwtPicker::PrivateData::PickerWidget::updateMask()
    00125 {
    00126     QRegion mask;
    00127
    00128     if ( d_type == RubberBand )
    00129     {
    00130         QBitmap bm(width(), height());
    00131         bm.fill(Qt::color0);
    00132
    00133         QPainter painter(&bm);
    00134         QPen pen = d_picker->rubberBandPen();
    00135         pen.setColor(Qt::color1);
    00136         painter.setPen(pen);
    00137
    00138         d_picker->drawRubberBand(&painter);
    00139
    00140         mask = QRegion(bm);
    00141     }
    00142     if ( d_type == Text )
    00143     {
    00144 #ifdef USE_TRACKER_RECT_MASK
    00145         QBitmap bm(width(), height());
    00146         QPainter painter(&bm);
    00147         painter.setFont(font());
    00148         mask = d_picker->trackerRect(&painter);
    00149 #else
    00150         QBitmap bm(width(), height());
    00151         bm.fill(Qt::color0);
    00152
    00153         QPainter painter(&bm);
    00154         painter.setFont(font());
    00155
    00156         QPen pen = d_picker->trackerPen();
    00157         pen.setColor(Qt::color1);
    00158         painter.setPen(pen);
    00159
    00160         d_picker->drawTracker(&painter);
    00161
    00162         mask = QRegion(bm);
    00163 #endif
    00164     }
    00165
    00166 #if QT_VERSION < 0x040000
    00167     QWidget *w = parentWidget();
    00168     const bool doUpdate = w->isUpdatesEnabled();
    00169     const Qt::BackgroundMode bgMode = w->backgroundMode();
    00170     w->setUpdatesEnabled(false);
    00171     if ( bgMode != Qt::NoBackground )
    00172         w->setBackgroundMode(Qt::NoBackground);
    00173 #endif
    00174
    00175     setMask(mask);
    00176
    00177 #if QT_VERSION < 0x040000
    00178     if ( bgMode != Qt::NoBackground )
    00179         w->setBackgroundMode(bgMode);
    00180
    00181     w->setUpdatesEnabled(doUpdate);
    00182 #endif
    00183
    00184     setShown(!mask.isEmpty());
    00185 }
    00186
    00187 void QwtPicker::PrivateData::PickerWidget::paintEvent(QPaintEvent *e)
    00188 {
    00189     QPainter painter(this);
    00190
    00191     if ( d_type == RubberBand )
    00192     {
    00193         painter.setClipRegion(e->region());
    00194         painter.setPen(d_picker->rubberBandPen());
    00195         d_picker->drawRubberBand(&painter);
    00196     }
    00197
    00198     if ( d_type == Text )
    00199     {
    00200         painter.setClipRegion(e->region());
    00201
    00202         bool doDrawTracker = true;
    00203 #ifndef USE_TRACKER_RECT_MASK
    00204 #ifdef USE_TRACKER_BACKGROUND
    00205         doDrawTracker = d_hasTrackerBackground;
    00206 #else
    00207         doDrawTracker = false;
    00208 #endif
    00209 #endif
    00210 #if QT_VERSION < 0x040000
    00211     if ( !doDrawTracker && QPainter::redirect(this) )
    00212     {
    00213         // setMask + painter redirection doesn't work
    00214         doDrawTracker = true;
    00215     }
    00216 #endif
    00217         if ( doDrawTracker )
    00218         {
    00219             painter.setPen(d_picker->trackerPen());
    00220             d_picker->drawTracker(&painter);
    00221         }
    00222         else
    00223             painter.fillRect(e->rect(), QBrush(d_picker->trackerPen().color()));
    00224     }
    00225 }
    00226
    00236 QwtPicker::QwtPicker(QWidget *parent):
    00237     QObject(parent)
    00238 {
    00239     init(parent, NoSelection, NoRubberBand, AlwaysOff);
    00240 }
    00241
    00251 QwtPicker::QwtPicker(int selectionFlags, RubberBand rubberBand,
    00252         DisplayMode trackerMode, QWidget *parent):
    00253     QObject(parent)
    00254 {
    00255     init(parent, selectionFlags, rubberBand, trackerMode);
    00256 }
    00257
    00259 QwtPicker::~QwtPicker()
    00260 {
    00261     setMouseTracking(false);
    00262     delete d_data->stateMachine;
    00263     delete d_data->rubberBandWidget;
    00264     delete d_data->trackerWidget;
    00265     delete d_data;
    00266 }
    00267
    00269 void QwtPicker::init(QWidget *parent, int selectionFlags,
    00270     RubberBand rubberBand, DisplayMode trackerMode)
    00271 {
    00272     d_data = new PrivateData;
    00273
    00274     d_data->rubberBandWidget = NULL;
    00275     d_data->trackerWidget = NULL;
    00276
    00277     d_data->rubberBand = rubberBand;
    00278     d_data->enabled = false;
    00279     d_data->resizeMode = Stretch;
    00280     d_data->trackerMode = AlwaysOff;
    00281     d_data->isActive = false;
    00282     d_data->labelPosition = QPoint(-1, -1);
    00283     d_data->mouseTracking = false;
    00284
    00285     d_data->stateMachine = NULL;
    00286     setSelectionFlags(selectionFlags);
    00287
    00288     if ( parent )
    00289     {
    00290 #if QT_VERSION >= 0x040000
    00291         if ( parent->focusPolicy() == Qt::NoFocus )
    00292             parent->setFocusPolicy(Qt::WheelFocus);
    00293 #else
    00294         if ( parent->focusPolicy() == QWidget::NoFocus )
    00295             parent->setFocusPolicy(QWidget::WheelFocus);
    00296 #endif
    00297
    00298         d_data->trackerFont = parent->font();
    00299         d_data->mouseTracking = parent->hasMouseTracking();
    00300         setEnabled(true);
    00301     }
    00302     setTrackerMode(trackerMode);
    00303 }
    00304
    00308 void QwtPicker::setStateMachine(QwtPickerMachine *stateMachine)
    00309 {
    00310     if ( d_data->stateMachine != stateMachine )
    00311     {
    00312         if ( isActive() )
    00313             end(false);
    00314
    00315         delete d_data->stateMachine;
    00316         d_data->stateMachine = stateMachine;
    00317
    00318         if ( d_data->stateMachine )
    00319             d_data->stateMachine->reset();
    00320     }
    00321 }
    00322
    00339 QwtPickerMachine *QwtPicker::stateMachine(int flags) const
    00340 {
    00341     if ( flags & PointSelection )
    00342     {
    00343         if ( flags & ClickSelection )
    00344             return new QwtPickerClickPointMachine;
    00345         else
    00346             return new QwtPickerDragPointMachine;
    00347     }
    00348     if ( flags & RectSelection )
    00349     {
    00350         if ( flags & ClickSelection )
    00351             return new QwtPickerClickRectMachine;
    00352         else
    00353             return new QwtPickerDragRectMachine;
    00354     }
    00355     if ( flags & PolygonSelection )
    00356     {
    00357         return new QwtPickerPolygonMachine();
    00358     }
    00359     return NULL;
    00360 }
    00361
    00363 QWidget *QwtPicker::parentWidget()
    00364 {
    00365     QObject *obj = parent();
    00366     if ( obj && obj->isWidgetType() )
    00367         return (QWidget *)obj;
    00368
    00369     return NULL;
    00370 }
    00371
    00373 const QWidget *QwtPicker::parentWidget() const
    00374 {
    00375     QObject *obj = parent();
    00376     if ( obj && obj->isWidgetType() )
    00377         return (QWidget *)obj;
    00378
    00379     return NULL;
    00380 }
    00381
    00391 void QwtPicker::setSelectionFlags(int flags)
    00392 {
    00393     d_data->selectionFlags = flags;
    00394     setStateMachine(stateMachine(flags));
    00395 }
    00396
    00402 int QwtPicker::selectionFlags() const
    00403 {
    00404     return d_data->selectionFlags;
    00405 }
    00406
    00415 void QwtPicker::setRubberBand(RubberBand rubberBand)
    00416 {
    00417     d_data->rubberBand = rubberBand;
    00418 }
    00419
    00424 QwtPicker::RubberBand QwtPicker::rubberBand() const
    00425 {
    00426     return d_data->rubberBand;
    00427 }
    00428
    00445 void QwtPicker::setTrackerMode(DisplayMode mode)
    00446 {
    00447     if ( d_data->trackerMode != mode )
    00448     {
    00449         d_data->trackerMode = mode;
    00450         setMouseTracking(d_data->trackerMode == AlwaysOn);
    00451     }
    00452 }
    00453
    00458 QwtPicker::DisplayMode QwtPicker::trackerMode() const
    00459 {
    00460     return d_data->trackerMode;
    00461 }
    00462
    00477 void QwtPicker::setResizeMode(ResizeMode mode)
    00478 {
    00479     d_data->resizeMode = mode;
    00480 }
    00481
    00487 QwtPicker::ResizeMode QwtPicker::resizeMode() const
    00488 {
    00489     return d_data->resizeMode;
    00490 }
    00491
    00501 void QwtPicker::setEnabled(bool enabled)
    00502 {
    00503     if ( d_data->enabled != enabled )
    00504     {
    00505         d_data->enabled = enabled;
    00506
    00507         QWidget *w = parentWidget();
    00508         if ( w )
    00509         {
    00510             if ( enabled )
    00511                 w->installEventFilter(this);
    00512             else
    00513                 w->removeEventFilter(this);
    00514         }
    00515
    00516         updateDisplay();
    00517     }
    00518 }
    00519
    00525 bool QwtPicker::isEnabled() const
    00526 {
    00527     return d_data->enabled;
    00528 }
    00529
    00536 void QwtPicker::setTrackerFont(const QFont &font)
    00537 {
    00538     if ( font != d_data->trackerFont )
    00539     {
    00540         d_data->trackerFont = font;
    00541         updateDisplay();
    00542     }
    00543 }
    00544
    00550 QFont QwtPicker::trackerFont() const
    00551 {
    00552     return d_data->trackerFont;
    00553 }
    00554
    00561 void QwtPicker::setTrackerPen(const QPen &pen)
    00562 {
    00563     if ( pen != d_data->trackerPen )
    00564     {
    00565         d_data->trackerPen = pen;
    00566         updateDisplay();
    00567     }
    00568 }
    00569
    00574 QPen QwtPicker::trackerPen() const
    00575 {
    00576     return d_data->trackerPen;
    00577 }
    00578
    00585 void QwtPicker::setRubberBandPen(const QPen &pen)
    00586 {
    00587     if ( pen != d_data->rubberBandPen )
    00588     {
    00589         d_data->rubberBandPen = pen;
    00590         updateDisplay();
    00591     }
    00592 }
    00593
    00598 QPen QwtPicker::rubberBandPen() const
    00599 {
    00600     return d_data->rubberBandPen;
    00601 }
    00602
    00616 QwtText QwtPicker::trackerText(const QPoint &pos) const
    00617 {
    00618     QString label;
    00619
    00620     switch(rubberBand())
    00621     {
    00622         case HLineRubberBand:
    00623             label.sprintf("%d", pos.y());
    00624             break;
    00625         case VLineRubberBand:
    00626             label.sprintf("%d", pos.x());
    00627             break;
    00628         default:
    00629             label.sprintf("%d, %d", pos.x(), pos.y());
    00630     }
    00631     return label;
    00632 }
    00633
    00642 void QwtPicker::drawRubberBand(QPainter *painter) const
    00643 {
    00644     if ( !isActive() || rubberBand() == NoRubberBand ||
    00645         rubberBandPen().style() == Qt::NoPen )
    00646     {
    00647         return;
    00648     }
    00649
    00650     const QRect &pRect = pickRect();
    00651     const QwtPolygon &pa = d_data->selection;
    00652
    00653     if ( selectionFlags() & PointSelection )
    00654     {
    00655         if ( pa.count() < 1 )
    00656             return;
    00657
    00658         const QPoint pos = pa[0];
    00659
    00660         switch(rubberBand())
    00661         {
    00662             case VLineRubberBand:
    00663                 QwtPainter::drawLine(painter, pos.x(),
    00664                     pRect.top(), pos.x(), pRect.bottom());
    00665                 break;
    00666
    00667             case HLineRubberBand:
    00668                 QwtPainter::drawLine(painter, pRect.left(),
    00669                     pos.y(), pRect.right(), pos.y());
    00670                 break;
    00671
    00672             case CrossRubberBand:
    00673                 QwtPainter::drawLine(painter, pos.x(),
    00674                     pRect.top(), pos.x(), pRect.bottom());
    00675                 QwtPainter::drawLine(painter, pRect.left(),
    00676                     pos.y(), pRect.right(), pos.y());
    00677                 break;
    00678             default:
    00679                 break;
    00680         }
    00681     }
    00682
    00683     else if ( selectionFlags() & RectSelection )
    00684     {
    00685         if ( pa.count() < 2 )
    00686             return;
    00687
    00688         QPoint p1 = pa[0];
    00689         QPoint p2 = pa[int(pa.count() - 1)];
    00690
    00691         if ( selectionFlags() & CenterToCorner )
    00692         {
    00693             p1.setX(p1.x() - (p2.x() - p1.x()));
    00694             p1.setY(p1.y() - (p2.y() - p1.y()));
    00695         }
    00696         else if ( selectionFlags() & CenterToRadius )
    00697         {
    00698             const int radius = qwtMax(qwtAbs(p2.x() - p1.x()),
    00699                 qwtAbs(p2.y() - p1.y()));
    00700             p2.setX(p1.x() + radius);
    00701             p2.setY(p1.y() + radius);
    00702             p1.setX(p1.x() - radius);
    00703             p1.setY(p1.y() - radius);
    00704         }
    00705
    00706 #if QT_VERSION < 0x040000
    00707         const QRect rect = QRect(p1, p2).normalize();
    00708 #else
    00709         const QRect rect = QRect(p1, p2).normalized();
    00710 #endif
    00711         switch(rubberBand())
    00712         {
    00713             case EllipseRubberBand:
    00714                 QwtPainter::drawEllipse(painter, rect);
    00715                 break;
    00716             case RectRubberBand:
    00717                 QwtPainter::drawRect(painter, rect);
    00718                 break;
    00719             default:
    00720                 break;
    00721         }
    00722     }
    00723     else if ( selectionFlags() & PolygonSelection )
    00724     {
    00725         if ( rubberBand() == PolygonRubberBand )
    00726             painter->drawPolyline(pa);
    00727     }
    00728 }
    00729
    00737 void QwtPicker::drawTracker(QPainter *painter) const
    00738 {
    00739     const QRect textRect = trackerRect(painter);
    00740     if ( !textRect.isEmpty() )
    00741     {
    00742         QwtText label = trackerText(d_data->labelPosition);
    00743         if ( !label.isEmpty() )
    00744         {
    00745 #ifdef USE_TRACKER_BACKGROUND
    00746             if ( label.testPaintAttribute(QwtText::PaintBackground) )
    00747             {
    00748                 if ( d_data->trackerWidget )
    00749                     d_data->trackerWidget->d_hasTrackerBackground = true;
    00750
    00751                 if ( painter->pen() != trackerPen() &&
    00752                     painter->pen().color() == Qt::color1 )
    00753                 {
    00754                     /*
    00755                       Hack time: we know, that we are painting to get the
    00756                       region for the mask. The text is always inside the
    00757                       textRect and on a QBitmap everything is painted in
    00758                       Qt::color1. That's why we don't have to paint the text.
    00759                      */
    00760                     painter->fillRect(textRect, Qt::color1);
    00761                     return;
    00762                 }
    00763             }
    00764             else
    00765             {
    00766                 if ( d_data->trackerWidget )
    00767                     d_data->trackerWidget->d_hasTrackerBackground = false;
    00768             }
    00769 #endif
    00770
    00771 #if defined(Q_WS_MAC)
    00772 #if QT_VERSION >= 0x040000 && QT_VERSION < 0x040300
    00773             // Antialiased fonts are broken on the Mac.
    00774             painter->save();
    00775             painter->setRenderHint(QPainter::TextAntialiasing, false);
    00776 #else
    00777             QFont fnt = label.usedFont(painter->font());
    00778             fnt.setStyleStrategy(QFont::NoAntialias);
    00779             label.setFont(fnt);
    00780 #endif
    00781 #endif
    00782             label.draw(painter, textRect);
    00783
    00784 #if defined(Q_WS_MAC)
    00785 #if QT_VERSION >= 0x040000 && QT_VERSION < 0x040300
    00786             painter->restore();
    00787 #endif
    00788 #endif
    00789         }
    00790     }
    00791 }
    00792
    00793 QRect QwtPicker::trackerRect(QPainter *painter) const
    00794 {
    00795     if ( trackerMode() == AlwaysOff ||
    00796         (trackerMode() == ActiveOnly && !isActive() ) )
    00797     {
    00798         return QRect();
    00799     }
    00800
    00801     if ( d_data->labelPosition.x() < 0 || d_data->labelPosition.y() < 0 )
    00802         return QRect();
    00803
    00804     QwtText text = trackerText(d_data->labelPosition);
    00805     if ( text.isEmpty() )
    00806         return QRect();
    00807
    00808     QRect textRect(QPoint(0, 0), text.textSize(painter->font()));
    00809
    00810     const QPoint &pos = d_data->labelPosition;
    00811
    00812     int alignment = 0;
    00813     if ( isActive() && d_data->selection.count() > 1
    00814         && rubberBand() != NoRubberBand )
    00815     {
    00816         const QPoint last =
    00817             d_data->selection[int(d_data->selection.count()) - 2];
    00818
    00819         alignment |= (pos.x() >= last.x()) ? Qt::AlignRight : Qt::AlignLeft;
    00820         alignment |= (pos.y() > last.y()) ? Qt::AlignBottom : Qt::AlignTop;
    00821     }
    00822     else
    00823         alignment = Qt::AlignTop | Qt::AlignRight;
    00824
    00825     const int margin = 5;
    00826
    00827     int x = pos.x();
    00828     if ( alignment & Qt::AlignLeft )
    00829         x -= textRect.width() + margin;
    00830     else if ( alignment & Qt::AlignRight )
    00831         x += margin;
    00832
    00833     int y = pos.y();
    00834     if ( alignment & Qt::AlignBottom )
    00835         y += margin;
    00836     else if ( alignment & Qt::AlignTop )
    00837         y -= textRect.height() + margin;
    00838
    00839     textRect.moveTopLeft(QPoint(x, y));
    00840
    00841     int right = qwtMin(textRect.right(), pickRect().right() - margin);
    00842     int bottom = qwtMin(textRect.bottom(), pickRect().bottom() - margin);
    00843     textRect.moveBottomRight(QPoint(right, bottom));
    00844
    00845     int left = qwtMax(textRect.left(), pickRect().left() + margin);
    00846     int top = qwtMax(textRect.top(), pickRect().top() + margin);
    00847     textRect.moveTopLeft(QPoint(left, top));
    00848
    00849     return textRect;
    00850 }
    00851
    00864 bool QwtPicker::eventFilter(QObject *o, QEvent *e)
    00865 {
    00866     if ( o && o == parentWidget() )
    00867     {
    00868         switch(e->type())
    00869         {
    00870             case QEvent::Resize:
    00871             {
    00872                 const QResizeEvent *re = (QResizeEvent *)e;
    00873                 if ( d_data->resizeMode == Stretch )
    00874                     stretchSelection(re->oldSize(), re->size());
    00875
    00876                 if ( d_data->rubberBandWidget )
    00877                     d_data->rubberBandWidget->resize(re->size());
    00878
    00879                 if ( d_data->trackerWidget )
    00880                     d_data->trackerWidget->resize(re->size());
    00881                 break;
    00882             }
    00883             case QEvent::Leave:
    00884                 widgetLeaveEvent(e);
    00885                 break;
    00886             case QEvent::MouseButtonPress:
    00887                 widgetMousePressEvent((QMouseEvent *)e);
    00888                 break;
    00889             case QEvent::MouseButtonRelease:
    00890                 widgetMouseReleaseEvent((QMouseEvent *)e);
    00891                 break;
    00892             case QEvent::MouseButtonDblClick:
    00893                 widgetMouseDoubleClickEvent((QMouseEvent *)e);
    00894                 break;
    00895             case QEvent::MouseMove:
    00896                 widgetMouseMoveEvent((QMouseEvent *)e);
    00897                 break;
    00898             case QEvent::KeyPress:
    00899                 widgetKeyPressEvent((QKeyEvent *)e);
    00900                 break;
    00901             case QEvent::KeyRelease:
    00902                 widgetKeyReleaseEvent((QKeyEvent *)e);
    00903                 break;
    00904             case QEvent::Wheel:
    00905                 widgetWheelEvent((QWheelEvent *)e);
    00906                 break;
    00907             default:
    00908                 break;
    00909         }
    00910     }
    00911     return false;
    00912 }
    00913
    00924 void QwtPicker::widgetMousePressEvent(QMouseEvent *e)
    00925 {
    00926     transition(e);
    00927 }
    00928
    00938 void QwtPicker::widgetMouseMoveEvent(QMouseEvent *e)
    00939 {
    00940     if ( pickRect().contains(e->pos()) )
    00941         d_data->labelPosition = e->pos();
    00942     else
    00943         d_data->labelPosition = QPoint(-1, -1);
    00944
    00945     if ( !isActive() )
    00946         updateDisplay();
    00947
    00948     transition(e);
    00949 }
    00950
    00958 void QwtPicker::widgetLeaveEvent(QEvent *)
    00959 {
    00960     d_data->labelPosition = QPoint(-1, -1);
    00961     if ( !isActive() )
    00962         updateDisplay();
    00963 }
    00964
    00975 void QwtPicker::widgetMouseReleaseEvent(QMouseEvent *e)
    00976 {
    00977     transition(e);
    00978 }
    00979
    00989 void QwtPicker::widgetMouseDoubleClickEvent(QMouseEvent *me)
    00990 {
    00991     transition(me);
    00992 }
    00993
    00994
    01004 void QwtPicker::widgetWheelEvent(QWheelEvent *e)
    01005 {
    01006     if ( pickRect().contains(e->pos()) )
    01007         d_data->labelPosition = e->pos();
    01008     else
    01009         d_data->labelPosition = QPoint(-1, -1);
    01010
    01011     updateDisplay();
    01012
    01013     transition(e);
    01014 }
    01015
    01029 void QwtPicker::widgetKeyPressEvent(QKeyEvent *ke)
    01030 {
    01031     int dx = 0;
    01032     int dy = 0;
    01033
    01034     int offset = 1;
    01035     if ( ke->isAutoRepeat() )
    01036         offset = 5;
    01037
    01038     if ( keyMatch(KeyLeft, ke) )
    01039         dx = -offset;
    01040     else if ( keyMatch(KeyRight, ke) )
    01041         dx = offset;
    01042     else if ( keyMatch(KeyUp, ke) )
    01043         dy = -offset;
    01044     else if ( keyMatch(KeyDown, ke) )
    01045         dy = offset;
    01046     else if ( keyMatch(KeyAbort, ke) )
    01047     {
    01048         if ( d_data->stateMachine )
    01049             d_data->stateMachine->reset();
    01050
    01051         if (isActive())
    01052             end(false);
    01053     }
    01054     else
    01055         transition(ke);
    01056
    01057     if ( dx != 0 || dy != 0 )
    01058     {
    01059         const QRect rect = pickRect();
    01060         const QPoint pos = parentWidget()->mapFromGlobal(QCursor::pos());
    01061
    01062         int x = pos.x() + dx;
    01063         x = qwtMax(rect.left(), x);
    01064         x = qwtMin(rect.right(), x);
    01065
    01066         int y = pos.y() + dy;
    01067         y = qwtMax(rect.top(), y);
    01068         y = qwtMin(rect.bottom(), y);
    01069
    01070         QCursor::setPos(parentWidget()->mapToGlobal(QPoint(x, y)));
    01071     }
    01072 }
    01073
    01083 void QwtPicker::widgetKeyReleaseEvent(QKeyEvent *ke)
    01084 {
    01085     transition(ke);
    01086 }
    01087
    01095 void QwtPicker::transition(const QEvent *e)
    01096 {
    01097     if ( !d_data->stateMachine )
    01098         return;
    01099
    01100     QwtPickerMachine::CommandList commandList =
    01101         d_data->stateMachine->transition(*this, e);
    01102
    01103     QPoint pos;
    01104     switch(e->type())
    01105     {
    01106         case QEvent::MouseButtonDblClick:
    01107         case QEvent::MouseButtonPress:
    01108         case QEvent::MouseButtonRelease:
    01109         case QEvent::MouseMove:
    01110         {
    01111             const QMouseEvent *me = (QMouseEvent *)e;
    01112             pos = me->pos();
    01113             break;
    01114         }
    01115         default:
    01116             pos = parentWidget()->mapFromGlobal(QCursor::pos());
    01117     }
    01118
    01119     for ( uint i = 0; i < (uint)commandList.count(); i++ )
    01120     {
    01121         switch(commandList[i])
    01122         {
    01123             case QwtPickerMachine::Begin:
    01124             {
    01125                 begin();
    01126                 break;
    01127             }
    01128             case QwtPickerMachine::Append:
    01129             {
    01130                 append(pos);
    01131                 break;
    01132             }
    01133             case QwtPickerMachine::Move:
    01134             {
    01135                 move(pos);
    01136                 break;
    01137             }
    01138             case QwtPickerMachine::End:
    01139             {
    01140                 end();
    01141                 break;
    01142             }
    01143         }
    01144     }
    01145 }
    01146
    01152 void QwtPicker::begin()
    01153 {
    01154     if ( d_data->isActive )
    01155         return;
    01156
    01157     d_data->selection.resize(0);
    01158     d_data->isActive = true;
    01159
    01160     if ( trackerMode() != AlwaysOff )
    01161     {
    01162         if ( d_data->labelPosition.x() < 0 || d_data->labelPosition.y() < 0 )
    01163         {
    01164             QWidget *w = parentWidget();
    01165             if ( w )
    01166                 d_data->labelPosition = w->mapFromGlobal(QCursor::pos());
    01167         }
    01168     }
    01169
    01170     updateDisplay();
    01171     setMouseTracking(true);
    01172 }
    01173
    01184 bool QwtPicker::end(bool ok)
    01185 {
    01186     if ( d_data->isActive )
    01187     {
    01188         setMouseTracking(false);
    01189
    01190         d_data->isActive = false;
    01191
    01192         if ( trackerMode() == ActiveOnly )
    01193             d_data->labelPosition = QPoint(-1, -1);
    01194
    01195         if ( ok )
    01196             ok = accept(d_data->selection);
    01197
    01198         if ( ok )
    01199             emit selected(d_data->selection);
    01200         else
    01201             d_data->selection.resize(0);
    01202
    01203         updateDisplay();
    01204     }
    01205     else
    01206         ok = false;
    01207
    01208     return ok;
    01209 }
    01210
    01219 void QwtPicker::append(const QPoint &pos)
    01220 {
    01221     if ( d_data->isActive )
    01222     {
    01223         const int idx = d_data->selection.count();
    01224         d_data->selection.resize(idx + 1);
    01225         d_data->selection[idx] = pos;
    01226
    01227         updateDisplay();
    01228
    01229         emit appended(pos);
    01230     }
    01231 }
    01232
    01241 void QwtPicker::move(const QPoint &pos)
    01242 {
    01243     if ( d_data->isActive )
    01244     {
    01245         const int idx = d_data->selection.count() - 1;
    01246         if ( idx >= 0 )
    01247         {
    01248             if ( d_data->selection[idx] != pos )
    01249             {
    01250                 d_data->selection[idx] = pos;
    01251
    01252                 updateDisplay();
    01253
    01254                 emit moved(pos);
    01255             }
    01256         }
    01257     }
    01258 }
    01259
    01260 bool QwtPicker::accept(QwtPolygon &) const
    01261 {
    01262     return true;
    01263 }
    01264
    01269 bool QwtPicker::isActive() const
    01270 {
    01271     return d_data->isActive;
    01272 }
    01273
    01275 const QwtPolygon &QwtPicker::selection() const
    01276 {
    01277     return d_data->selection;
    01278 }
    01279
    01289 void QwtPicker::stretchSelection(const QSize &oldSize, const QSize &newSize)
    01290 {
    01291     const double xRatio =
    01292         double(newSize.width()) / double(oldSize.width());
    01293     const double yRatio =
    01294         double(newSize.height()) / double(oldSize.height());
    01295
    01296     for ( int i = 0; i < int(d_data->selection.count()); i++ )
    01297     {
    01298         QPoint &p = d_data->selection[i];
    01299         p.setX(qRound(p.x() * xRatio));
    01300         p.setY(qRound(p.y() * yRatio));
    01301
    01302         emit changed(d_data->selection);
    01303     }
    01304 }
    01305
    01319 void QwtPicker::setMouseTracking(bool enable)
    01320 {
    01321     QWidget *widget = parentWidget();
    01322     if ( !widget )
    01323         return;
    01324
    01325     if ( enable )
    01326     {
    01327         d_data->mouseTracking = widget->hasMouseTracking();
    01328         widget->setMouseTracking(true);
    01329     }
    01330     else
    01331     {
    01332         widget->setMouseTracking(d_data->mouseTracking);
    01333     }
    01334 }
    01335
    01341 QRect QwtPicker::pickRect() const
    01342 {
    01343     QRect rect;
    01344
    01345     const QWidget *widget = parentWidget();
    01346     if ( !widget )
    01347         return rect;
    01348
    01349     if ( widget->inherits("QFrame") )
    01350         rect = ((QFrame *)widget)->contentsRect();
    01351     else
    01352         rect = widget->rect();
    01353
    01354     return rect;
    01355 }
    01356
    01357 void QwtPicker::updateDisplay()
    01358 {
    01359     QWidget *w = parentWidget();
    01360
    01361     bool showRubberband = false;
    01362     bool showTracker = false;
    01363     if ( w && w->isVisible() && d_data->enabled )
    01364     {
    01365         if ( rubberBand() != NoRubberBand && isActive() &&
    01366             rubberBandPen().style() != Qt::NoPen )
    01367         {
    01368             showRubberband = true;
    01369         }
    01370
    01371         if ( trackerMode() == AlwaysOn ||
    01372             (trackerMode() == ActiveOnly && isActive() ) )
    01373         {
    01374             if ( trackerPen() != Qt::NoPen )
    01375                 showTracker = true;
    01376         }
    01377     }
    01378
    01379 #if QT_VERSION < 0x040000
    01380     QGuardedPtr<PrivateData::PickerWidget> &rw = d_data->rubberBandWidget;
    01381 #else
    01382     QPointer<PrivateData::PickerWidget> &rw = d_data->rubberBandWidget;
    01383 #endif
    01384     if ( showRubberband )
    01385     {
    01386         if ( rw.isNull() )
    01387         {
    01388             rw = new PrivateData::PickerWidget(
    01389                 this, w, PrivateData::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<PrivateData::PickerWidget> &tw = d_data->trackerWidget;
    01400 #else
    01401     QPointer<PrivateData::PickerWidget> &tw = d_data->trackerWidget;
    01402 #endif
    01403     if ( showTracker )
    01404     {
    01405         if ( tw.isNull() )
    01406         {
    01407             tw = new PrivateData::PickerWidget(
    01408                 this, w, PrivateData::PickerWidget::Text);
    01409             tw->resize(w->size());
    01410         }
    01411         tw->updateMask();
    01412         tw->update(); // Needed, when the mask doesn't change
    01413     }
    01414     else
    01415         delete tw;
    01416 }
    01417
    01418 const QWidget *QwtPicker::rubberBandWidget() const
    01419 {
    01420     return d_data->rubberBandWidget;
    01421 }
    01422
    01423 const QWidget *QwtPicker::trackerWidget() const
    01424 {
    01425     return d_data->trackerWidget;
    01426 }
    01427