00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_picker.h"
00011 #include "qwt_picker_machine.h"
00012 #include "qwt_painter.h"
00013 #include "qwt_math.h"
00014 #include "qwt_widget_overlay.h"
00015 #include <qapplication.h>
00016 #include <qevent.h>
00017 #include <qpainter.h>
00018 #include <qframe.h>
00019 #include <qcursor.h>
00020 #include <qbitmap.h>
00021 #include <qpointer.h>
00022 #include <qpaintengine.h>
00023 #include <qmath.h>
00024
00025 static inline QRegion qwtMaskRegion( const QRect &r, int penWidth )
00026 {
00027 const int pw = qMax( penWidth, 1 );
00028 const int pw2 = penWidth / 2;
00029
00030 int x1 = r.left() - pw2;
00031 int x2 = r.right() + 1 + pw2 + ( pw % 2 );
00032
00033 int y1 = r.top() - pw2;
00034 int y2 = r.bottom() + 1 + pw2 + ( pw % 2 );
00035
00036 QRegion region;
00037
00038 region += QRect( x1, y1, x2 - x1, pw );
00039 region += QRect( x1, y1, pw, y2 - y1 );
00040 region += QRect( x1, y2 - pw, x2 - x1, pw );
00041 region += QRect( x2 - pw, y1, pw, y2 - y1 );
00042
00043 return region;
00044 }
00045
00046 static inline QRegion qwtMaskRegion( const QLine &l, int penWidth )
00047 {
00048 const int pw = qMax( penWidth, 1 );
00049 const int pw2 = penWidth / 2;
00050
00051 QRegion region;
00052
00053 if ( l.x1() == l.x2() )
00054 {
00055 region += QRect( l.x1() - pw2, l.y1(),
00056 pw, l.y2() ).normalized();
00057 }
00058 else if ( l.y1() == l.y2() )
00059 {
00060 region += QRect( l.x1(), l.y1() - pw2,
00061 l.x2(), pw ).normalized();
00062 }
00063
00064 return region;
00065 }
00066
00067 class QwtPickerRubberband: public QwtWidgetOverlay
00068 {
00069 public:
00070 QwtPickerRubberband( QwtPicker *, QWidget * );
00071
00072 protected:
00073 virtual void drawOverlay( QPainter * ) const;
00074 virtual QRegion maskHint() const;
00075
00076 QwtPicker *d_picker;
00077 };
00078
00079 class QwtPickerTracker: public QwtWidgetOverlay
00080 {
00081 public:
00082 QwtPickerTracker( QwtPicker *, QWidget * );
00083
00084 protected:
00085 virtual void drawOverlay( QPainter * ) const;
00086 virtual QRegion maskHint() const;
00087
00088 QwtPicker *d_picker;
00089 };
00090
00091
00092 class QwtPicker::PrivateData
00093 {
00094 public:
00095 PrivateData():
00096 enabled( false ),
00097 stateMachine( NULL ),
00098 resizeMode( QwtPicker::Stretch ),
00099 rubberBand( QwtPicker::NoRubberBand ),
00100 trackerMode( QwtPicker::AlwaysOff ),
00101 isActive( false ),
00102 trackerPosition( -1, -1 ),
00103 mouseTracking( false ),
00104 openGL( false )
00105 {
00106 }
00107
00108 bool enabled;
00109
00110 QwtPickerMachine *stateMachine;
00111
00112 QwtPicker::ResizeMode resizeMode;
00113
00114 QwtPicker::RubberBand rubberBand;
00115 QPen rubberBandPen;
00116
00117 QwtPicker::DisplayMode trackerMode;
00118 QPen trackerPen;
00119 QFont trackerFont;
00120
00121 QPolygon pickedPoints;
00122 bool isActive;
00123 QPoint trackerPosition;
00124
00125 bool mouseTracking;
00126
00127 QPointer< QwtPickerRubberband > rubberBandOverlay;
00128 QPointer< QwtPickerTracker> trackerOverlay;
00129
00130 bool openGL;
00131 };
00132
00133 QwtPickerRubberband::QwtPickerRubberband(
00134 QwtPicker *picker, QWidget *parent ):
00135 QwtWidgetOverlay( parent ),
00136 d_picker( picker )
00137 {
00138 setMaskMode( QwtWidgetOverlay::MaskHint );
00139 }
00140
00141 QRegion QwtPickerRubberband::maskHint() const
00142 {
00143 return d_picker->rubberBandMask();
00144 }
00145
00146 void QwtPickerRubberband::drawOverlay( QPainter *painter ) const
00147 {
00148 painter->setPen( d_picker->rubberBandPen() );
00149 d_picker->drawRubberBand( painter );
00150 }
00151
00152 QwtPickerTracker::QwtPickerTracker(
00153 QwtPicker *picker, QWidget *parent ):
00154 QwtWidgetOverlay( parent ),
00155 d_picker( picker )
00156 {
00157 setMaskMode( QwtWidgetOverlay::MaskHint );
00158 }
00159
00160 QRegion QwtPickerTracker::maskHint() const
00161 {
00162 return d_picker->trackerMask();
00163 }
00164
00165 void QwtPickerTracker::drawOverlay( QPainter *painter ) const
00166 {
00167 painter->setPen( d_picker->trackerPen() );
00168 d_picker->drawTracker( painter );
00169 }
00170
00180 QwtPicker::QwtPicker( QWidget *parent ):
00181 QObject( parent )
00182 {
00183 init( parent, NoRubberBand, AlwaysOff );
00184 }
00185
00193 QwtPicker::QwtPicker( RubberBand rubberBand,
00194 DisplayMode trackerMode, QWidget *parent ):
00195 QObject( parent )
00196 {
00197 init( parent, rubberBand, trackerMode );
00198 }
00199
00201 QwtPicker::~QwtPicker()
00202 {
00203 setMouseTracking( false );
00204
00205 delete d_data->stateMachine;
00206 delete d_data->rubberBandOverlay;
00207 delete d_data->trackerOverlay;
00208
00209 delete d_data;
00210 }
00211
00213 void QwtPicker::init( QWidget *parent,
00214 RubberBand rubberBand, DisplayMode trackerMode )
00215 {
00216 d_data = new PrivateData;
00217
00218 d_data->rubberBand = rubberBand;
00219
00220 if ( parent )
00221 {
00222 if ( parent->focusPolicy() == Qt::NoFocus )
00223 parent->setFocusPolicy( Qt::WheelFocus );
00224
00225 d_data->openGL = parent->inherits( "QGLWidget" );
00226 d_data->trackerFont = parent->font();
00227 d_data->mouseTracking = parent->hasMouseTracking();
00228
00229 setEnabled( true );
00230 }
00231
00232 setTrackerMode( trackerMode );
00233 }
00234
00241 void QwtPicker::setStateMachine( QwtPickerMachine *stateMachine )
00242 {
00243 if ( d_data->stateMachine != stateMachine )
00244 {
00245 reset();
00246
00247 delete d_data->stateMachine;
00248 d_data->stateMachine = stateMachine;
00249
00250 if ( d_data->stateMachine )
00251 d_data->stateMachine->reset();
00252 }
00253 }
00254
00259 QwtPickerMachine *QwtPicker::stateMachine()
00260 {
00261 return d_data->stateMachine;
00262 }
00263
00268 const QwtPickerMachine *QwtPicker::stateMachine() const
00269 {
00270 return d_data->stateMachine;
00271 }
00272
00274 QWidget *QwtPicker::parentWidget()
00275 {
00276 QObject *obj = parent();
00277 if ( obj && obj->isWidgetType() )
00278 return static_cast<QWidget *>( obj );
00279
00280 return NULL;
00281 }
00282
00284 const QWidget *QwtPicker::parentWidget() const
00285 {
00286 QObject *obj = parent();
00287 if ( obj && obj->isWidgetType() )
00288 return static_cast< const QWidget *>( obj );
00289
00290 return NULL;
00291 }
00292
00301 void QwtPicker::setRubberBand( RubberBand rubberBand )
00302 {
00303 d_data->rubberBand = rubberBand;
00304 }
00305
00310 QwtPicker::RubberBand QwtPicker::rubberBand() const
00311 {
00312 return d_data->rubberBand;
00313 }
00314
00331 void QwtPicker::setTrackerMode( DisplayMode mode )
00332 {
00333 if ( d_data->trackerMode != mode )
00334 {
00335 d_data->trackerMode = mode;
00336 setMouseTracking( d_data->trackerMode == AlwaysOn );
00337 }
00338 }
00339
00344 QwtPicker::DisplayMode QwtPicker::trackerMode() const
00345 {
00346 return d_data->trackerMode;
00347 }
00348
00363 void QwtPicker::setResizeMode( ResizeMode mode )
00364 {
00365 d_data->resizeMode = mode;
00366 }
00367
00373 QwtPicker::ResizeMode QwtPicker::resizeMode() const
00374 {
00375 return d_data->resizeMode;
00376 }
00377
00387 void QwtPicker::setEnabled( bool enabled )
00388 {
00389 if ( d_data->enabled != enabled )
00390 {
00391 d_data->enabled = enabled;
00392
00393 QWidget *w = parentWidget();
00394 if ( w )
00395 {
00396 if ( enabled )
00397 w->installEventFilter( this );
00398 else
00399 w->removeEventFilter( this );
00400 }
00401
00402 updateDisplay();
00403 }
00404 }
00405
00411 bool QwtPicker::isEnabled() const
00412 {
00413 return d_data->enabled;
00414 }
00415
00422 void QwtPicker::setTrackerFont( const QFont &font )
00423 {
00424 if ( font != d_data->trackerFont )
00425 {
00426 d_data->trackerFont = font;
00427 updateDisplay();
00428 }
00429 }
00430
00436 QFont QwtPicker::trackerFont() const
00437 {
00438 return d_data->trackerFont;
00439 }
00440
00447 void QwtPicker::setTrackerPen( const QPen &pen )
00448 {
00449 if ( pen != d_data->trackerPen )
00450 {
00451 d_data->trackerPen = pen;
00452 updateDisplay();
00453 }
00454 }
00455
00460 QPen QwtPicker::trackerPen() const
00461 {
00462 return d_data->trackerPen;
00463 }
00464
00471 void QwtPicker::setRubberBandPen( const QPen &pen )
00472 {
00473 if ( pen != d_data->rubberBandPen )
00474 {
00475 d_data->rubberBandPen = pen;
00476 updateDisplay();
00477 }
00478 }
00479
00484 QPen QwtPicker::rubberBandPen() const
00485 {
00486 return d_data->rubberBandPen;
00487 }
00488
00502 QwtText QwtPicker::trackerText( const QPoint &pos ) const
00503 {
00504 QString label;
00505
00506 switch ( rubberBand() )
00507 {
00508 case HLineRubberBand:
00509 label.sprintf( "%d", pos.y() );
00510 break;
00511 case VLineRubberBand:
00512 label.sprintf( "%d", pos.x() );
00513 break;
00514 default:
00515 label.sprintf( "%d, %d", pos.x(), pos.y() );
00516 }
00517 return label;
00518 }
00519
00526 QRegion QwtPicker::trackerMask() const
00527 {
00528 return trackerRect( d_data->trackerFont );
00529 }
00530
00537 QRegion QwtPicker::rubberBandMask() const
00538 {
00539 QRegion mask;
00540
00541 if ( !isActive() || rubberBand() == NoRubberBand ||
00542 rubberBandPen().style() == Qt::NoPen )
00543 {
00544 return mask;
00545 }
00546
00547 const QPolygon pa = adjustedPoints( d_data->pickedPoints );
00548
00549 QwtPickerMachine::SelectionType selectionType =
00550 QwtPickerMachine::NoSelection;
00551
00552 if ( d_data->stateMachine )
00553 selectionType = d_data->stateMachine->selectionType();
00554
00555 switch ( selectionType )
00556 {
00557 case QwtPickerMachine::NoSelection:
00558 case QwtPickerMachine::PointSelection:
00559 {
00560 if ( pa.count() < 1 )
00561 return mask;
00562
00563 const QPoint pos = pa[0];
00564 const int pw = rubberBandPen().width();
00565
00566 const QRect pRect = pickArea().boundingRect().toRect();
00567 switch ( rubberBand() )
00568 {
00569 case VLineRubberBand:
00570 {
00571 mask += qwtMaskRegion( QLine( pos.x(), pRect.top(),
00572 pos.x(), pRect.bottom() ), pw );
00573 break;
00574 }
00575 case HLineRubberBand:
00576 {
00577 mask += qwtMaskRegion( QLine( pRect.left(), pos.y(),
00578 pRect.right(), pos.y() ), pw );
00579 break;
00580 }
00581 case CrossRubberBand:
00582 {
00583 mask += qwtMaskRegion( QLine( pos.x(), pRect.top(),
00584 pos.x(), pRect.bottom() ), pw );
00585 mask += qwtMaskRegion( QLine( pRect.left(), pos.y(),
00586 pRect.right(), pos.y() ), pw );
00587 break;
00588 }
00589 default:
00590 break;
00591 }
00592 break;
00593 }
00594 case QwtPickerMachine::RectSelection:
00595 {
00596 if ( pa.count() < 2 )
00597 return mask;
00598
00599 const int pw = rubberBandPen().width();
00600
00601 switch ( rubberBand() )
00602 {
00603 case RectRubberBand:
00604 {
00605 const QRect r = QRect( pa.first(), pa.last() );
00606 mask = qwtMaskRegion( r.normalized(), pw );
00607 break;
00608 }
00609 case EllipseRubberBand:
00610 {
00611 const QRect r = QRect( pa.first(), pa.last() );
00612 mask += r.adjusted( -pw, -pw, pw, pw );
00613 break;
00614 }
00615 default:
00616 break;
00617 }
00618 break;
00619 }
00620 case QwtPickerMachine::PolygonSelection:
00621 {
00622 const int pw = rubberBandPen().width();
00623 if ( pw <= 1 )
00624 {
00625
00626
00627
00628 const int off = 2 * pw;
00629 const QRect r = pa.boundingRect();
00630 mask += r.adjusted( -off, -off, off, off );
00631 }
00632 break;
00633 }
00634 default:
00635 break;
00636 }
00637
00638 return mask;
00639 }
00640
00649 void QwtPicker::drawRubberBand( QPainter *painter ) const
00650 {
00651 if ( !isActive() || rubberBand() == NoRubberBand ||
00652 rubberBandPen().style() == Qt::NoPen )
00653 {
00654 return;
00655 }
00656
00657 const QPolygon pa = adjustedPoints( d_data->pickedPoints );
00658
00659 QwtPickerMachine::SelectionType selectionType =
00660 QwtPickerMachine::NoSelection;
00661
00662 if ( d_data->stateMachine )
00663 selectionType = d_data->stateMachine->selectionType();
00664
00665 switch ( selectionType )
00666 {
00667 case QwtPickerMachine::NoSelection:
00668 case QwtPickerMachine::PointSelection:
00669 {
00670 if ( pa.count() < 1 )
00671 return;
00672
00673 const QPoint pos = pa[0];
00674
00675 const QRect pRect = pickArea().boundingRect().toRect();
00676 switch ( rubberBand() )
00677 {
00678 case VLineRubberBand:
00679 {
00680 QwtPainter::drawLine( painter, pos.x(),
00681 pRect.top(), pos.x(), pRect.bottom() );
00682 break;
00683 }
00684 case HLineRubberBand:
00685 {
00686 QwtPainter::drawLine( painter, pRect.left(),
00687 pos.y(), pRect.right(), pos.y() );
00688 break;
00689 }
00690 case CrossRubberBand:
00691 {
00692 QwtPainter::drawLine( painter, pos.x(),
00693 pRect.top(), pos.x(), pRect.bottom() );
00694 QwtPainter::drawLine( painter, pRect.left(),
00695 pos.y(), pRect.right(), pos.y() );
00696 break;
00697 }
00698 default:
00699 break;
00700 }
00701 break;
00702 }
00703 case QwtPickerMachine::RectSelection:
00704 {
00705 if ( pa.count() < 2 )
00706 return;
00707
00708 const QRect rect = QRect( pa.first(), pa.last() ).normalized();
00709 switch ( rubberBand() )
00710 {
00711 case EllipseRubberBand:
00712 {
00713 QwtPainter::drawEllipse( painter, rect );
00714 break;
00715 }
00716 case RectRubberBand:
00717 {
00718 QwtPainter::drawRect( painter, rect );
00719 break;
00720 }
00721 default:
00722 break;
00723 }
00724 break;
00725 }
00726 case QwtPickerMachine::PolygonSelection:
00727 {
00728 if ( rubberBand() == PolygonRubberBand )
00729 painter->drawPolyline( pa );
00730 break;
00731 }
00732 default:
00733 break;
00734 }
00735 }
00736
00744 void QwtPicker::drawTracker( QPainter *painter ) const
00745 {
00746 const QRect textRect = trackerRect( painter->font() );
00747 if ( !textRect.isEmpty() )
00748 {
00749 const QwtText label = trackerText( d_data->trackerPosition );
00750 if ( !label.isEmpty() )
00751 label.draw( painter, textRect );
00752 }
00753 }
00754
00792 QPolygon QwtPicker::adjustedPoints( const QPolygon &points ) const
00793 {
00794 return points;
00795 }
00796
00801 QPolygon QwtPicker::selection() const
00802 {
00803 return adjustedPoints( d_data->pickedPoints );
00804 }
00805
00807 QPoint QwtPicker::trackerPosition() const
00808 {
00809 return d_data->trackerPosition;
00810 }
00811
00821 QRect QwtPicker::trackerRect( const QFont &font ) const
00822 {
00823 if ( trackerMode() == AlwaysOff ||
00824 ( trackerMode() == ActiveOnly && !isActive() ) )
00825 {
00826 return QRect();
00827 }
00828
00829 if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
00830 return QRect();
00831
00832 QwtText text = trackerText( d_data->trackerPosition );
00833 if ( text.isEmpty() )
00834 return QRect();
00835
00836 const QSizeF textSize = text.textSize( font );
00837 QRect textRect( 0, 0, qCeil( textSize.width() ), qCeil( textSize.height() ) );
00838
00839 const QPoint &pos = d_data->trackerPosition;
00840
00841 int alignment = 0;
00842 if ( isActive() && d_data->pickedPoints.count() > 1
00843 && rubberBand() != NoRubberBand )
00844 {
00845 const QPoint last =
00846 d_data->pickedPoints[int( d_data->pickedPoints.count() ) - 2];
00847
00848 alignment |= ( pos.x() >= last.x() ) ? Qt::AlignRight : Qt::AlignLeft;
00849 alignment |= ( pos.y() > last.y() ) ? Qt::AlignBottom : Qt::AlignTop;
00850 }
00851 else
00852 alignment = Qt::AlignTop | Qt::AlignRight;
00853
00854 const int margin = 5;
00855
00856 int x = pos.x();
00857 if ( alignment & Qt::AlignLeft )
00858 x -= textRect.width() + margin;
00859 else if ( alignment & Qt::AlignRight )
00860 x += margin;
00861
00862 int y = pos.y();
00863 if ( alignment & Qt::AlignBottom )
00864 y += margin;
00865 else if ( alignment & Qt::AlignTop )
00866 y -= textRect.height() + margin;
00867
00868 textRect.moveTopLeft( QPoint( x, y ) );
00869
00870 const QRect pickRect = pickArea().boundingRect().toRect();
00871
00872 int right = qMin( textRect.right(), pickRect.right() - margin );
00873 int bottom = qMin( textRect.bottom(), pickRect.bottom() - margin );
00874 textRect.moveBottomRight( QPoint( right, bottom ) );
00875
00876 int left = qMax( textRect.left(), pickRect.left() + margin );
00877 int top = qMax( textRect.top(), pickRect.top() + margin );
00878 textRect.moveTopLeft( QPoint( left, top ) );
00879
00880 return textRect;
00881 }
00882
00902 bool QwtPicker::eventFilter( QObject *object, QEvent *event )
00903 {
00904 if ( object && object == parentWidget() )
00905 {
00906 switch ( event->type() )
00907 {
00908 case QEvent::Resize:
00909 {
00910 const QResizeEvent *re = static_cast<QResizeEvent *>( event );
00911
00912
00913
00914
00915
00916
00917
00918 if ( d_data->trackerOverlay )
00919 d_data->trackerOverlay->resize( re->size() );
00920
00921 if ( d_data->rubberBandOverlay )
00922 d_data->rubberBandOverlay->resize( re->size() );
00923
00924 if ( d_data->resizeMode == Stretch )
00925 stretchSelection( re->oldSize(), re->size() );
00926
00927 updateDisplay();
00928 break;
00929 }
00930 case QEvent::Enter:
00931 {
00932 widgetEnterEvent( event );
00933 break;
00934 }
00935 case QEvent::Leave:
00936 {
00937 widgetLeaveEvent( event );
00938 break;
00939 }
00940 case QEvent::MouseButtonPress:
00941 {
00942 widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
00943 break;
00944 }
00945 case QEvent::MouseButtonRelease:
00946 {
00947 widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
00948 break;
00949 }
00950 case QEvent::MouseButtonDblClick:
00951 {
00952 widgetMouseDoubleClickEvent( static_cast<QMouseEvent *>( event ) );
00953 break;
00954 }
00955 case QEvent::MouseMove:
00956 {
00957 widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
00958 break;
00959 }
00960 case QEvent::KeyPress:
00961 {
00962 widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
00963 break;
00964 }
00965 case QEvent::KeyRelease:
00966 {
00967 widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
00968 break;
00969 }
00970 case QEvent::Wheel:
00971 {
00972 widgetWheelEvent( static_cast<QWheelEvent *>( event ) );
00973 break;
00974 }
00975 default:
00976 break;
00977 }
00978 }
00979 return false;
00980 }
00981
00991 void QwtPicker::widgetMousePressEvent( QMouseEvent *mouseEvent )
00992 {
00993 transition( mouseEvent );
00994 }
00995
01005 void QwtPicker::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
01006 {
01007 if ( pickArea().contains( mouseEvent->pos() ) )
01008 d_data->trackerPosition = mouseEvent->pos();
01009 else
01010 d_data->trackerPosition = QPoint( -1, -1 );
01011
01012 if ( !isActive() )
01013 updateDisplay();
01014
01015 transition( mouseEvent );
01016 }
01017
01027 void QwtPicker::widgetEnterEvent( QEvent *event )
01028 {
01029 transition( event );
01030 }
01031
01041 void QwtPicker::widgetLeaveEvent( QEvent *event )
01042 {
01043 transition( event );
01044
01045 d_data->trackerPosition = QPoint( -1, -1 );
01046 if ( !isActive() )
01047 updateDisplay();
01048 }
01049
01059 void QwtPicker::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
01060 {
01061 transition( mouseEvent );
01062 }
01063
01073 void QwtPicker::widgetMouseDoubleClickEvent( QMouseEvent *mouseEvent )
01074 {
01075 transition( mouseEvent );
01076 }
01077
01078
01090 void QwtPicker::widgetWheelEvent( QWheelEvent *wheelEvent )
01091 {
01092 if ( pickArea().contains( wheelEvent->pos() ) )
01093 d_data->trackerPosition = wheelEvent->pos();
01094 else
01095 d_data->trackerPosition = QPoint( -1, -1 );
01096
01097 updateDisplay();
01098
01099 transition( wheelEvent );
01100 }
01101
01116 void QwtPicker::widgetKeyPressEvent( QKeyEvent *keyEvent )
01117 {
01118 int dx = 0;
01119 int dy = 0;
01120
01121 int offset = 1;
01122 if ( keyEvent->isAutoRepeat() )
01123 offset = 5;
01124
01125 if ( keyMatch( KeyLeft, keyEvent ) )
01126 dx = -offset;
01127 else if ( keyMatch( KeyRight, keyEvent ) )
01128 dx = offset;
01129 else if ( keyMatch( KeyUp, keyEvent ) )
01130 dy = -offset;
01131 else if ( keyMatch( KeyDown, keyEvent ) )
01132 dy = offset;
01133 else if ( keyMatch( KeyAbort, keyEvent ) )
01134 {
01135 reset();
01136 }
01137 else
01138 transition( keyEvent );
01139
01140 if ( dx != 0 || dy != 0 )
01141 {
01142 const QRect rect = pickArea().boundingRect().toRect();
01143 const QPoint pos = parentWidget()->mapFromGlobal( QCursor::pos() );
01144
01145 int x = pos.x() + dx;
01146 x = qMax( rect.left(), x );
01147 x = qMin( rect.right(), x );
01148
01149 int y = pos.y() + dy;
01150 y = qMax( rect.top(), y );
01151 y = qMin( rect.bottom(), y );
01152
01153 QCursor::setPos( parentWidget()->mapToGlobal( QPoint( x, y ) ) );
01154 }
01155 }
01156
01168 void QwtPicker::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
01169 {
01170 transition( keyEvent );
01171 }
01172
01180 void QwtPicker::transition( const QEvent *event )
01181 {
01182 if ( !d_data->stateMachine )
01183 return;
01184
01185 const QList<QwtPickerMachine::Command> commandList =
01186 d_data->stateMachine->transition( *this, event );
01187
01188 QPoint pos;
01189 switch ( event->type() )
01190 {
01191 case QEvent::MouseButtonDblClick:
01192 case QEvent::MouseButtonPress:
01193 case QEvent::MouseButtonRelease:
01194 case QEvent::MouseMove:
01195 {
01196 const QMouseEvent *me =
01197 static_cast< const QMouseEvent * >( event );
01198 pos = me->pos();
01199 break;
01200 }
01201 default:
01202 pos = parentWidget()->mapFromGlobal( QCursor::pos() );
01203 }
01204
01205 for ( int i = 0; i < commandList.count(); i++ )
01206 {
01207 switch ( commandList[i] )
01208 {
01209 case QwtPickerMachine::Begin:
01210 {
01211 begin();
01212 break;
01213 }
01214 case QwtPickerMachine::Append:
01215 {
01216 append( pos );
01217 break;
01218 }
01219 case QwtPickerMachine::Move:
01220 {
01221 move( pos );
01222 break;
01223 }
01224 case QwtPickerMachine::Remove:
01225 {
01226 remove();
01227 break;
01228 }
01229 case QwtPickerMachine::End:
01230 {
01231 end();
01232 break;
01233 }
01234 }
01235 }
01236 }
01237
01243 void QwtPicker::begin()
01244 {
01245 if ( d_data->isActive )
01246 return;
01247
01248 d_data->pickedPoints.resize( 0 );
01249 d_data->isActive = true;
01250 Q_EMIT activated( true );
01251
01252 if ( trackerMode() != AlwaysOff )
01253 {
01254 if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
01255 {
01256 QWidget *w = parentWidget();
01257 if ( w )
01258 d_data->trackerPosition = w->mapFromGlobal( QCursor::pos() );
01259 }
01260 }
01261
01262 updateDisplay();
01263 setMouseTracking( true );
01264 }
01265
01276 bool QwtPicker::end( bool ok )
01277 {
01278 if ( d_data->isActive )
01279 {
01280 setMouseTracking( false );
01281
01282 d_data->isActive = false;
01283 Q_EMIT activated( false );
01284
01285 if ( trackerMode() == ActiveOnly )
01286 d_data->trackerPosition = QPoint( -1, -1 );
01287
01288 if ( ok )
01289 ok = accept( d_data->pickedPoints );
01290
01291 if ( ok )
01292 Q_EMIT selected( d_data->pickedPoints );
01293 else
01294 d_data->pickedPoints.resize( 0 );
01295
01296 updateDisplay();
01297 }
01298 else
01299 ok = false;
01300
01301 return ok;
01302 }
01303
01307 void QwtPicker::reset()
01308 {
01309 if ( d_data->stateMachine )
01310 d_data->stateMachine->reset();
01311
01312 if ( isActive() )
01313 end( false );
01314 }
01315
01324 void QwtPicker::append( const QPoint &pos )
01325 {
01326 if ( d_data->isActive )
01327 {
01328 const int idx = d_data->pickedPoints.count();
01329 d_data->pickedPoints.resize( idx + 1 );
01330 d_data->pickedPoints[idx] = pos;
01331
01332 updateDisplay();
01333 Q_EMIT appended( pos );
01334 }
01335 }
01336
01344 void QwtPicker::move( const QPoint &pos )
01345 {
01346 if ( d_data->isActive )
01347 {
01348 const int idx = d_data->pickedPoints.count() - 1;
01349 if ( idx >= 0 )
01350 {
01351 if ( d_data->pickedPoints[idx] != pos )
01352 {
01353 d_data->pickedPoints[idx] = pos;
01354
01355 updateDisplay();
01356 Q_EMIT moved( pos );
01357 }
01358 }
01359 }
01360 }
01361
01368 void QwtPicker::remove()
01369 {
01370 if ( d_data->isActive )
01371 {
01372 const int idx = d_data->pickedPoints.count() - 1;
01373 if ( idx > 0 )
01374 {
01375 const int idx = d_data->pickedPoints.count();
01376
01377 const QPoint pos = d_data->pickedPoints[idx - 1];
01378 d_data->pickedPoints.resize( idx - 1 );
01379
01380 updateDisplay();
01381 Q_EMIT removed( pos );
01382 }
01383 }
01384 }
01385
01394 bool QwtPicker::accept( QPolygon &selection ) const
01395 {
01396 Q_UNUSED( selection );
01397 return true;
01398 }
01399
01404 bool QwtPicker::isActive() const
01405 {
01406 return d_data->isActive;
01407 }
01408
01414 const QPolygon &QwtPicker::pickedPoints() const
01415 {
01416 return d_data->pickedPoints;
01417 }
01418
01428 void QwtPicker::stretchSelection( const QSize &oldSize, const QSize &newSize )
01429 {
01430 if ( oldSize.isEmpty() )
01431 {
01432
01433
01434 return;
01435 }
01436
01437 const double xRatio =
01438 double( newSize.width() ) / double( oldSize.width() );
01439 const double yRatio =
01440 double( newSize.height() ) / double( oldSize.height() );
01441
01442 for ( int i = 0; i < int( d_data->pickedPoints.count() ); i++ )
01443 {
01444 QPoint &p = d_data->pickedPoints[i];
01445 p.setX( qRound( p.x() * xRatio ) );
01446 p.setY( qRound( p.y() * yRatio ) );
01447
01448 Q_EMIT changed( d_data->pickedPoints );
01449 }
01450 }
01451
01465 void QwtPicker::setMouseTracking( bool enable )
01466 {
01467 QWidget *widget = parentWidget();
01468 if ( !widget )
01469 return;
01470
01471 if ( enable )
01472 {
01473 d_data->mouseTracking = widget->hasMouseTracking();
01474 widget->setMouseTracking( true );
01475 }
01476 else
01477 {
01478 widget->setMouseTracking( d_data->mouseTracking );
01479 }
01480 }
01481
01487 QPainterPath QwtPicker::pickArea() const
01488 {
01489 QPainterPath path;
01490
01491 const QWidget *widget = parentWidget();
01492 if ( widget )
01493 path.addRect( widget->contentsRect() );
01494
01495 return path;
01496 }
01497
01499 void QwtPicker::updateDisplay()
01500 {
01501 QWidget *w = parentWidget();
01502
01503 bool showRubberband = false;
01504 bool showTracker = false;
01505
01506 if ( w && w->isVisible() && d_data->enabled )
01507 {
01508 if ( rubberBand() != NoRubberBand && isActive() &&
01509 rubberBandPen().style() != Qt::NoPen )
01510 {
01511 showRubberband = true;
01512 }
01513
01514 if ( trackerMode() == AlwaysOn ||
01515 ( trackerMode() == ActiveOnly && isActive() ) )
01516 {
01517 if ( trackerPen() != Qt::NoPen
01518 && !trackerRect( QFont() ).isEmpty() )
01519 {
01520 showTracker = true;
01521 }
01522 }
01523 }
01524
01525 QPointer< QwtPickerRubberband > &rw = d_data->rubberBandOverlay;
01526 if ( showRubberband )
01527 {
01528 if ( rw.isNull() )
01529 {
01530 rw = new QwtPickerRubberband( this, NULL );
01531 rw->setObjectName( "PickerRubberBand" );
01532 rw->setParent( w );
01533 rw->resize( w->size() );
01534 }
01535
01536 if ( d_data->rubberBand <= RectRubberBand )
01537 rw->setMaskMode( QwtWidgetOverlay::MaskHint );
01538 else
01539 rw->setMaskMode( QwtWidgetOverlay::AlphaMask );
01540
01541 rw->updateOverlay();
01542 }
01543 else
01544 {
01545 if ( d_data->openGL )
01546 {
01547
01548 if ( !rw.isNull() )
01549 {
01550 rw->hide();
01551 rw->deleteLater();
01552 rw = NULL;
01553 }
01554 }
01555 else
01556 {
01557 delete rw;
01558 }
01559 }
01560
01561 QPointer< QwtPickerTracker > &tw = d_data->trackerOverlay;
01562 if ( showTracker )
01563 {
01564 if ( tw.isNull() )
01565 {
01566 tw = new QwtPickerTracker( this, NULL );
01567 tw->setObjectName( "PickerTracker" );
01568 tw->setParent( w );
01569 tw->resize( w->size() );
01570 }
01571 tw->setFont( d_data->trackerFont );
01572 tw->updateOverlay();
01573 }
01574 else
01575 {
01576 if ( d_data->openGL )
01577 {
01578
01579 if ( !tw.isNull() )
01580 {
01581 tw->hide();
01582 tw->deleteLater();
01583 tw = NULL;
01584 }
01585 }
01586 else
01587 {
01588 delete tw;
01589 }
01590 }
01591 }
01592
01594 const QwtWidgetOverlay *QwtPicker::rubberBandOverlay() const
01595 {
01596 return d_data->rubberBandOverlay;
01597 }
01598
01600 const QwtWidgetOverlay *QwtPicker::trackerOverlay() const
01601 {
01602 return d_data->trackerOverlay;
01603 }
01604