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 

Generated on Thu May 1 15:44:08 2008 for Qwt User's Guide by  doxygen 1.5.0