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 

Generated on Sun Mar 22 16:54:07 2009 for Qwt User's Guide by  doxygen 1.5.0