Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
qwt_picker.cpp
1/******************************************************************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10#include "qwt_picker.h"
11#include "qwt_picker_machine.h"
12#include "qwt_painter.h"
13#include "qwt_math.h"
14#include "qwt_widget_overlay.h"
15#include "qwt_text.h"
16
17#include <qevent.h>
18#include <qpainter.h>
19#include <qpainterpath.h>
20#include <qcursor.h>
21#include <qpointer.h>
22#include <qmath.h>
23
24static inline QRegion qwtMaskRegion( const QRect& r, int penWidth )
25{
26 const int pw = qMax( penWidth, 1 );
27 const int pw2 = penWidth / 2;
28
29 int x1 = r.left() - pw2;
30 int x2 = r.right() + 1 + pw2 + ( pw % 2 );
31
32 int y1 = r.top() - pw2;
33 int y2 = r.bottom() + 1 + pw2 + ( pw % 2 );
34
35 QRegion region;
36
37 region += QRect( x1, y1, x2 - x1, pw );
38 region += QRect( x1, y1, pw, y2 - y1 );
39 region += QRect( x1, y2 - pw, x2 - x1, pw );
40 region += QRect( x2 - pw, y1, pw, y2 - y1 );
41
42 return region;
43}
44
45static inline QRegion qwtMaskRegion( const QLine& l, int penWidth )
46{
47 const int pw = qMax( penWidth, 1 );
48 const int pw2 = penWidth / 2;
49
50 QRegion region;
51
52 if ( l.x1() == l.x2() )
53 {
54 region += QRect( l.x1() - pw2, l.y1(),
55 pw, l.y2() ).normalized();
56 }
57 else if ( l.y1() == l.y2() )
58 {
59 region += QRect( l.x1(), l.y1() - pw2,
60 l.x2(), pw ).normalized();
61 }
62
63 return region;
64}
65
66namespace
67{
68 class Rubberband QWT_FINAL : public QwtWidgetOverlay
69 {
70 public:
71 Rubberband( QwtPicker* picker, QWidget* parent )
72 : QwtWidgetOverlay( parent )
73 , m_picker( picker )
74 {
75 setMaskMode( QwtWidgetOverlay::MaskHint );
76 }
77
78 protected:
79 virtual void drawOverlay( QPainter* painter ) const QWT_OVERRIDE
80 {
81 painter->setPen( m_picker->rubberBandPen() );
82 m_picker->drawRubberBand( painter );
83 }
84
85 virtual QRegion maskHint() const QWT_OVERRIDE
86 {
87 return m_picker->rubberBandMask();
88 }
89
90 QwtPicker* m_picker;
91 };
92
93 class Tracker QWT_FINAL : public QwtWidgetOverlay
94 {
95 public:
96 Tracker( QwtPicker* picker, QWidget* parent )
97 : QwtWidgetOverlay( parent )
98 , m_picker( picker )
99 {
100 setMaskMode( QwtWidgetOverlay::MaskHint );
101 }
102
103 protected:
104 virtual void drawOverlay( QPainter* painter ) const QWT_OVERRIDE
105 {
106 painter->setPen( m_picker->trackerPen() );
107 m_picker->drawTracker( painter );
108 }
109
110 virtual QRegion maskHint() const QWT_OVERRIDE
111 {
112 return m_picker->trackerMask();
113 }
114
115 QwtPicker* m_picker;
116 };
117}
118
119class QwtPicker::PrivateData
120{
121 public:
122 PrivateData():
123 enabled( false ),
124 stateMachine( NULL ),
125 resizeMode( QwtPicker::Stretch ),
126 rubberBand( QwtPicker::NoRubberBand ),
127 trackerMode( QwtPicker::AlwaysOff ),
128 isActive( false ),
129 trackerPosition( -1, -1 ),
130 mouseTracking( false ),
131 openGL( false )
132 {
133 }
134
135 bool enabled;
136
137 QwtPickerMachine* stateMachine;
138
139 QwtPicker::ResizeMode resizeMode;
140
141 QwtPicker::RubberBand rubberBand;
142 QPen rubberBandPen;
143
144 QwtPicker::DisplayMode trackerMode;
145 QPen trackerPen;
146 QFont trackerFont;
147
148 QPolygon pickedPoints;
149 bool isActive;
150 QPoint trackerPosition;
151
152 bool mouseTracking; // used to save previous value
153
154 QPointer< Rubberband > rubberBandOverlay;
155 QPointer< Tracker > trackerOverlay;
156
157 bool openGL;
158};
159
169QwtPicker::QwtPicker( QWidget* parent ):
170 QObject( parent )
171{
172 init( parent, NoRubberBand, AlwaysOff );
173}
174
183 DisplayMode trackerMode, QWidget* parent ):
184 QObject( parent )
185{
186 init( parent, rubberBand, trackerMode );
187}
188
191{
192 setMouseTracking( false );
193
194 delete m_data->stateMachine;
195 delete m_data->rubberBandOverlay;
196 delete m_data->trackerOverlay;
197
198 delete m_data;
199}
200
202void QwtPicker::init( QWidget* parent,
203 RubberBand rubberBand, DisplayMode trackerMode )
204{
205 m_data = new PrivateData;
206
207 m_data->rubberBand = rubberBand;
208
209 if ( parent )
210 {
211 if ( parent->focusPolicy() == Qt::NoFocus )
212 parent->setFocusPolicy( Qt::WheelFocus );
213
214 m_data->openGL = parent->inherits( "QGLWidget" );
215 m_data->trackerFont = parent->font();
216 m_data->mouseTracking = parent->hasMouseTracking();
217
218 setEnabled( true );
219 }
220
222}
223
231{
232 if ( m_data->stateMachine != stateMachine )
233 {
234 reset();
235
236 delete m_data->stateMachine;
237 m_data->stateMachine = stateMachine;
238
239 if ( m_data->stateMachine )
240 m_data->stateMachine->reset();
241 }
242}
243
249{
250 return m_data->stateMachine;
251}
252
258{
259 return m_data->stateMachine;
260}
261
264{
265 QObject* obj = parent();
266 if ( obj && obj->isWidgetType() )
267 return static_cast< QWidget* >( obj );
268
269 return NULL;
270}
271
273const QWidget* QwtPicker::parentWidget() const
274{
275 QObject* obj = parent();
276 if ( obj && obj->isWidgetType() )
277 return static_cast< const QWidget* >( obj );
278
279 return NULL;
280}
281
291{
292 m_data->rubberBand = rubberBand;
293}
294
300{
301 return m_data->rubberBand;
302}
303
321{
322 if ( m_data->trackerMode != mode )
323 {
324 m_data->trackerMode = mode;
325 setMouseTracking( m_data->trackerMode == AlwaysOn );
326 }
327}
328
334{
335 return m_data->trackerMode;
336}
337
353{
354 m_data->resizeMode = mode;
355}
356
363{
364 return m_data->resizeMode;
365}
366
376void QwtPicker::setEnabled( bool enabled )
377{
378 if ( m_data->enabled != enabled )
379 {
380 m_data->enabled = enabled;
381
382 QWidget* w = parentWidget();
383 if ( w )
384 {
385 if ( enabled )
386 w->installEventFilter( this );
387 else
388 w->removeEventFilter( this );
389 }
390
392 }
393}
394
401{
402 return m_data->enabled;
403}
404
411void QwtPicker::setTrackerFont( const QFont& font )
412{
413 if ( font != m_data->trackerFont )
414 {
415 m_data->trackerFont = font;
417 }
418}
419
426{
427 return m_data->trackerFont;
428}
429
436void QwtPicker::setTrackerPen( const QPen& pen )
437{
438 if ( pen != m_data->trackerPen )
439 {
440 m_data->trackerPen = pen;
442 }
443}
444
450{
451 return m_data->trackerPen;
452}
453
460void QwtPicker::setRubberBandPen( const QPen& pen )
461{
462 if ( pen != m_data->rubberBandPen )
463 {
464 m_data->rubberBandPen = pen;
466 }
467}
468
474{
475 return m_data->rubberBandPen;
476}
477
491QwtText QwtPicker::trackerText( const QPoint& pos ) const
492{
493 QString label;
494
495 switch ( rubberBand() )
496 {
497 case HLineRubberBand:
498 label = QString::number( pos.y() );
499 break;
500 case VLineRubberBand:
501 label = QString::number( pos.x() );
502 break;
503 default:
504 label = QString::number( pos.x() ) + ", " + QString::number( pos.y() );
505 }
506 return label;
507}
508
516{
517 return trackerRect( m_data->trackerFont );
518}
519
527{
528 QRegion mask;
529
530 if ( !isActive() || rubberBand() == NoRubberBand ||
531 rubberBandPen().style() == Qt::NoPen )
532 {
533 return mask;
534 }
535
536 const QPolygon pa = adjustedPoints( m_data->pickedPoints );
537
538 QwtPickerMachine::SelectionType selectionType =
540
541 if ( m_data->stateMachine )
542 selectionType = m_data->stateMachine->selectionType();
543
544 const int pw = qCeil( rubberBandPen().widthF()
546
547 switch ( selectionType )
548 {
551 {
552 if ( pa.count() < 1 )
553 return mask;
554
555 const QPoint pos = pa[0];
556
557 const QRect pRect = pickArea().boundingRect().toRect();
558 switch ( rubberBand() )
559 {
560 case VLineRubberBand:
561 {
562 mask += qwtMaskRegion( QLine( pos.x(), pRect.top(),
563 pos.x(), pRect.bottom() ), pw );
564 break;
565 }
566 case HLineRubberBand:
567 {
568 mask += qwtMaskRegion( QLine( pRect.left(), pos.y(),
569 pRect.right(), pos.y() ), pw );
570 break;
571 }
572 case CrossRubberBand:
573 {
574 mask += qwtMaskRegion( QLine( pos.x(), pRect.top(),
575 pos.x(), pRect.bottom() ), pw );
576 mask += qwtMaskRegion( QLine( pRect.left(), pos.y(),
577 pRect.right(), pos.y() ), pw );
578 break;
579 }
580 default:
581 break;
582 }
583 break;
584 }
586 {
587 if ( pa.count() < 2 )
588 return mask;
589
590 switch ( rubberBand() )
591 {
592 case RectRubberBand:
593 {
594 const QRect r = QRect( pa.first(), pa.last() );
595 mask = qwtMaskRegion( r.normalized(), pw );
596 break;
597 }
599 {
600 const QRect r = QRect( pa.first(), pa.last() );
601 mask += r.adjusted( -pw, -pw, pw, pw );
602 break;
603 }
604 default:
605 break;
606 }
607 break;
608 }
610 {
611 if ( pw <= 1 )
612 {
613 // because of the join style we better
614 // return a mask for a pen width <= 1 only
615
616 const int off = 2 * pw;
617 const QRect r = pa.boundingRect();
618 mask += r.adjusted( -off, -off, off, off );
619 }
620 break;
621 }
622 default:
623 break;
624 }
625
626 return mask;
627}
628
637void QwtPicker::drawRubberBand( QPainter* painter ) const
638{
639 if ( !isActive() || rubberBand() == NoRubberBand ||
640 rubberBandPen().style() == Qt::NoPen )
641 {
642 return;
643 }
644
645 const QPolygon pa = adjustedPoints( m_data->pickedPoints );
646
647 QwtPickerMachine::SelectionType selectionType =
649
650 if ( m_data->stateMachine )
651 selectionType = m_data->stateMachine->selectionType();
652
653 switch ( selectionType )
654 {
657 {
658 if ( pa.count() < 1 )
659 return;
660
661 const QPoint pos = pa[0];
662
663 const QRect pRect = pickArea().boundingRect().toRect();
664 switch ( rubberBand() )
665 {
666 case VLineRubberBand:
667 {
668 QwtPainter::drawLine( painter, pos.x(),
669 pRect.top(), pos.x(), pRect.bottom() );
670 break;
671 }
672 case HLineRubberBand:
673 {
674 QwtPainter::drawLine( painter, pRect.left(),
675 pos.y(), pRect.right(), pos.y() );
676 break;
677 }
678 case CrossRubberBand:
679 {
680 QwtPainter::drawLine( painter, pos.x(),
681 pRect.top(), pos.x(), pRect.bottom() );
682 QwtPainter::drawLine( painter, pRect.left(),
683 pos.y(), pRect.right(), pos.y() );
684 break;
685 }
686 default:
687 break;
688 }
689 break;
690 }
692 {
693 if ( pa.count() < 2 )
694 return;
695
696 const QRect rect = QRect( pa.first(), pa.last() ).normalized();
697 switch ( rubberBand() )
698 {
700 {
701 QwtPainter::drawEllipse( painter, rect );
702 break;
703 }
704 case RectRubberBand:
705 {
706 QwtPainter::drawRect( painter, rect );
707 break;
708 }
709 default:
710 break;
711 }
712 break;
713 }
715 {
716 if ( rubberBand() == PolygonRubberBand )
717 painter->drawPolyline( pa );
718 break;
719 }
720 default:
721 break;
722 }
723}
724
732void QwtPicker::drawTracker( QPainter* painter ) const
733{
734 const QRect textRect = trackerRect( painter->font() );
735 if ( !textRect.isEmpty() )
736 {
737 const QwtText label = trackerText( m_data->trackerPosition );
738 if ( !label.isEmpty() )
739 label.draw( painter, textRect );
740 }
741}
742
783QPolygon QwtPicker::adjustedPoints( const QPolygon& points ) const
784{
785 return points;
786}
787
792QPolygon QwtPicker::selection() const
793{
794 return adjustedPoints( m_data->pickedPoints );
795}
796
799{
800 return m_data->trackerPosition;
801}
802
812QRect QwtPicker::trackerRect( const QFont& font ) const
813{
814 if ( trackerMode() == AlwaysOff ||
815 ( trackerMode() == ActiveOnly && !isActive() ) )
816 {
817 return QRect();
818 }
819
820 if ( m_data->trackerPosition.x() < 0 || m_data->trackerPosition.y() < 0 )
821 return QRect();
822
823 QwtText text = trackerText( m_data->trackerPosition );
824 if ( text.isEmpty() )
825 return QRect();
826
827 const QSizeF textSize = text.textSize( font );
828
829 const int w = qwtCeil( textSize.width() );
830 const int h = qwtCeil( textSize.height() );
831
832 return trackerRect( QSize( w, h ) );
833}
834
844QRect QwtPicker::trackerRect( const QSize& size ) const
845{
846 const QPoint& pos = m_data->trackerPosition;
847 QRect infoRect( 0, 0, size.width(), size.height() );
848
849 int alignment = 0;
850 if ( isActive() && m_data->pickedPoints.count() > 1
851 && rubberBand() != NoRubberBand )
852 {
853 const QPoint last =
854 m_data->pickedPoints[ m_data->pickedPoints.count() - 2 ];
855
856 alignment |= ( pos.x() >= last.x() ) ? Qt::AlignRight : Qt::AlignLeft;
857 alignment |= ( pos.y() > last.y() ) ? Qt::AlignBottom : Qt::AlignTop;
858 }
859 else
860 {
861 alignment = Qt::AlignTop | Qt::AlignRight;
862 }
863
864 const int margin = 5;
865
866 int x = pos.x();
867 if ( alignment & Qt::AlignLeft )
868 x -= infoRect.width() + margin;
869 else if ( alignment & Qt::AlignRight )
870 x += margin;
871
872 int y = pos.y();
873 if ( alignment & Qt::AlignBottom )
874 y += margin;
875 else if ( alignment & Qt::AlignTop )
876 y -= infoRect.height() + margin;
877
878 infoRect.moveTopLeft( QPoint( x, y ) );
879
880 const QRect pickRect = pickArea().boundingRect().toRect();
881
882 int right = qMin( infoRect.right(), pickRect.right() - margin );
883 int bottom = qMin( infoRect.bottom(), pickRect.bottom() - margin );
884 infoRect.moveBottomRight( QPoint( right, bottom ) );
885
886 int left = qMax( infoRect.left(), pickRect.left() + margin );
887 int top = qMax( infoRect.top(), pickRect.top() + margin );
888 infoRect.moveTopLeft( QPoint( left, top ) );
889
890 return infoRect;
891}
892
912bool QwtPicker::eventFilter( QObject* object, QEvent* event )
913{
914 if ( object && object == parentWidget() )
915 {
916 switch ( event->type() )
917 {
918 case QEvent::Resize:
919 {
920 const QResizeEvent* re = static_cast< QResizeEvent* >( event );
921
922 /*
923 Adding/deleting additional event filters inside of an event filter
924 is not safe dues to the implementation in Qt ( changing a list while iterating ).
925 So we create the overlays in a way, that they don't install en event filter
926 ( parent set to NULL ) and do the resizing here.
927 */
928 if ( m_data->trackerOverlay )
929 m_data->trackerOverlay->resize( re->size() );
930
931 if ( m_data->rubberBandOverlay )
932 m_data->rubberBandOverlay->resize( re->size() );
933
934 if ( m_data->resizeMode == Stretch )
935 stretchSelection( re->oldSize(), re->size() );
936
938 break;
939 }
940 case QEvent::Enter:
941 {
942 widgetEnterEvent( event );
943 break;
944 }
945 case QEvent::Leave:
946 {
947 widgetLeaveEvent( event );
948 break;
949 }
950 case QEvent::MouseButtonPress:
951 {
952 widgetMousePressEvent( static_cast< QMouseEvent* >( event ) );
953 break;
954 }
955 case QEvent::MouseButtonRelease:
956 {
957 widgetMouseReleaseEvent( static_cast< QMouseEvent* >( event ) );
958 break;
959 }
960 case QEvent::MouseButtonDblClick:
961 {
962 widgetMouseDoubleClickEvent( static_cast< QMouseEvent* >( event ) );
963 break;
964 }
965 case QEvent::MouseMove:
966 {
967 widgetMouseMoveEvent( static_cast< QMouseEvent* >( event ) );
968 break;
969 }
970 case QEvent::KeyPress:
971 {
972 widgetKeyPressEvent( static_cast< QKeyEvent* >( event ) );
973 break;
974 }
975 case QEvent::KeyRelease:
976 {
977 widgetKeyReleaseEvent( static_cast< QKeyEvent* >( event ) );
978 break;
979 }
980 case QEvent::Wheel:
981 {
982 widgetWheelEvent( static_cast< QWheelEvent* >( event ) );
983 break;
984 }
985 default:
986 break;
987 }
988 }
989 return false;
990}
991
1001void QwtPicker::widgetMousePressEvent( QMouseEvent* mouseEvent )
1002{
1003 transition( mouseEvent );
1004}
1005
1015void QwtPicker::widgetMouseMoveEvent( QMouseEvent* mouseEvent )
1016{
1017 if ( pickArea().contains( mouseEvent->pos() ) )
1018 m_data->trackerPosition = mouseEvent->pos();
1019 else
1020 m_data->trackerPosition = QPoint( -1, -1 );
1021
1022 if ( !isActive() )
1023 updateDisplay();
1024
1025 transition( mouseEvent );
1026}
1027
1037void QwtPicker::widgetEnterEvent( QEvent* event )
1038{
1039 transition( event );
1040}
1041
1051void QwtPicker::widgetLeaveEvent( QEvent* event )
1052{
1053 transition( event );
1054
1055 m_data->trackerPosition = QPoint( -1, -1 );
1056 if ( !isActive() )
1057 updateDisplay();
1058}
1059
1069void QwtPicker::widgetMouseReleaseEvent( QMouseEvent* mouseEvent )
1070{
1071 transition( mouseEvent );
1072}
1073
1083void QwtPicker::widgetMouseDoubleClickEvent( QMouseEvent* mouseEvent )
1084{
1085 transition( mouseEvent );
1086}
1087
1088
1100void QwtPicker::widgetWheelEvent( QWheelEvent* wheelEvent )
1101{
1102#if QT_VERSION < 0x050e00
1103 const QPoint wheelPos = wheelEvent->pos();
1104#else
1105 const QPoint wheelPos = wheelEvent->position().toPoint();
1106#endif
1107 if ( pickArea().contains( wheelPos ) )
1108 m_data->trackerPosition = wheelPos;
1109 else
1110 m_data->trackerPosition = QPoint( -1, -1 );
1111
1112 updateDisplay();
1113
1114 transition( wheelEvent );
1115}
1116
1131void QwtPicker::widgetKeyPressEvent( QKeyEvent* keyEvent )
1132{
1133 int dx = 0;
1134 int dy = 0;
1135
1136 int offset = 1;
1137 if ( keyEvent->isAutoRepeat() )
1138 offset = 5;
1139
1140 if ( keyMatch( KeyLeft, keyEvent ) )
1141 dx = -offset;
1142 else if ( keyMatch( KeyRight, keyEvent ) )
1143 dx = offset;
1144 else if ( keyMatch( KeyUp, keyEvent ) )
1145 dy = -offset;
1146 else if ( keyMatch( KeyDown, keyEvent ) )
1147 dy = offset;
1148 else if ( keyMatch( KeyAbort, keyEvent ) )
1149 {
1150 reset();
1151 }
1152 else
1153 transition( keyEvent );
1154
1155 if ( dx != 0 || dy != 0 )
1156 {
1157 const QRect rect = pickArea().boundingRect().toRect();
1158 const QPoint pos = parentWidget()->mapFromGlobal( QCursor::pos() );
1159
1160 int x = pos.x() + dx;
1161 x = qMax( rect.left(), x );
1162 x = qMin( rect.right(), x );
1163
1164 int y = pos.y() + dy;
1165 y = qMax( rect.top(), y );
1166 y = qMin( rect.bottom(), y );
1167
1168 QCursor::setPos( parentWidget()->mapToGlobal( QPoint( x, y ) ) );
1169 }
1170}
1171
1183void QwtPicker::widgetKeyReleaseEvent( QKeyEvent* keyEvent )
1184{
1185 transition( keyEvent );
1186}
1187
1195void QwtPicker::transition( const QEvent* event )
1196{
1197 if ( !m_data->stateMachine )
1198 return;
1199
1200 const QList< QwtPickerMachine::Command > commandList =
1201 m_data->stateMachine->transition( *this, event );
1202
1203 QPoint pos;
1204 switch ( event->type() )
1205 {
1206 case QEvent::MouseButtonDblClick:
1207 case QEvent::MouseButtonPress:
1208 case QEvent::MouseButtonRelease:
1209 case QEvent::MouseMove:
1210 {
1211 const QMouseEvent* me =
1212 static_cast< const QMouseEvent* >( event );
1213 pos = me->pos();
1214 break;
1215 }
1216 default:
1217 pos = parentWidget()->mapFromGlobal( QCursor::pos() );
1218 }
1219
1220 for ( int i = 0; i < commandList.count(); i++ )
1221 {
1222 switch ( commandList[i] )
1223 {
1224 case QwtPickerMachine::Begin:
1225 {
1226 begin();
1227 break;
1228 }
1229 case QwtPickerMachine::Append:
1230 {
1231 append( pos );
1232 break;
1233 }
1234 case QwtPickerMachine::Move:
1235 {
1236 move( pos );
1237 break;
1238 }
1239 case QwtPickerMachine::Remove:
1240 {
1241 remove();
1242 break;
1243 }
1244 case QwtPickerMachine::End:
1245 {
1246 end();
1247 break;
1248 }
1249 }
1250 }
1251}
1252
1259{
1260 if ( m_data->isActive )
1261 return;
1262
1263 m_data->pickedPoints.clear();
1264 m_data->isActive = true;
1265 Q_EMIT activated( true );
1266
1267 if ( trackerMode() != AlwaysOff )
1268 {
1269 if ( m_data->trackerPosition.x() < 0 || m_data->trackerPosition.y() < 0 )
1270 {
1271 QWidget* w = parentWidget();
1272 if ( w )
1273 m_data->trackerPosition = w->mapFromGlobal( QCursor::pos() );
1274 }
1275 }
1276
1277 updateDisplay();
1278 setMouseTracking( true );
1279}
1280
1291bool QwtPicker::end( bool ok )
1292{
1293 if ( m_data->isActive )
1294 {
1295 setMouseTracking( false );
1296
1297 m_data->isActive = false;
1298 Q_EMIT activated( false );
1299
1300 if ( trackerMode() == ActiveOnly )
1301 m_data->trackerPosition = QPoint( -1, -1 );
1302
1303 if ( ok )
1304 ok = accept( m_data->pickedPoints );
1305
1306 if ( ok )
1307 Q_EMIT selected( m_data->pickedPoints );
1308 else
1309 m_data->pickedPoints.clear();
1310
1311 updateDisplay();
1312 }
1313 else
1314 ok = false;
1315
1316 return ok;
1317}
1318
1323{
1324 if ( m_data->stateMachine )
1325 m_data->stateMachine->reset();
1326
1327 if ( isActive() )
1328 end( false );
1329}
1330
1339void QwtPicker::append( const QPoint& pos )
1340{
1341 if ( m_data->isActive )
1342 {
1343 m_data->pickedPoints += pos;
1344
1345 updateDisplay();
1346 Q_EMIT appended( pos );
1347 }
1348}
1349
1357void QwtPicker::move( const QPoint& pos )
1358{
1359 if ( m_data->isActive && !m_data->pickedPoints.isEmpty() )
1360 {
1361 QPoint& point = m_data->pickedPoints.last();
1362 if ( point != pos )
1363 {
1364 point = pos;
1365
1366 updateDisplay();
1367 Q_EMIT moved( pos );
1368 }
1369 }
1370}
1371
1379{
1380 if ( m_data->isActive && !m_data->pickedPoints.isEmpty() )
1381 {
1382#if QT_VERSION >= 0x050100
1383 const QPoint pos = m_data->pickedPoints.takeLast();
1384#else
1385 const QPoint pos = m_data->pickedPoints.last();
1386 m_data->pickedPoints.resize( m_data->pickedPoints.count() - 1 );
1387#endif
1388
1389 updateDisplay();
1390 Q_EMIT removed( pos );
1391 }
1392}
1393
1402bool QwtPicker::accept( QPolygon& selection ) const
1403{
1404 Q_UNUSED( selection );
1405 return true;
1406}
1407
1413{
1414 return m_data->isActive;
1415}
1416
1422const QPolygon& QwtPicker::pickedPoints() const
1423{
1424 return m_data->pickedPoints;
1425}
1426
1436void QwtPicker::stretchSelection( const QSize& oldSize, const QSize& newSize )
1437{
1438 if ( oldSize.isEmpty() )
1439 {
1440 // avoid division by zero. But scaling for small sizes also
1441 // doesn't make much sense, because of rounding losses. TODO ...
1442 return;
1443 }
1444
1445 const double xRatio = double( newSize.width() ) / double( oldSize.width() );
1446 const double yRatio = double( newSize.height() ) / double( oldSize.height() );
1447
1448 for ( int i = 0; i < m_data->pickedPoints.count(); i++ )
1449 {
1450 QPoint& p = m_data->pickedPoints[i];
1451 p.setX( qRound( p.x() * xRatio ) );
1452 p.setY( qRound( p.y() * yRatio ) );
1453
1454 Q_EMIT changed( m_data->pickedPoints );
1455 }
1456}
1457
1471void QwtPicker::setMouseTracking( bool enable )
1472{
1473 QWidget* widget = parentWidget();
1474 if ( !widget )
1475 return;
1476
1477 if ( enable )
1478 {
1479 m_data->mouseTracking = widget->hasMouseTracking();
1480 widget->setMouseTracking( true );
1481 }
1482 else
1483 {
1484 widget->setMouseTracking( m_data->mouseTracking );
1485 }
1486}
1487
1493QPainterPath QwtPicker::pickArea() const
1494{
1495 QPainterPath path;
1496
1497 const QWidget* widget = parentWidget();
1498 if ( widget )
1499 path.addRect( widget->contentsRect() );
1500
1501 return path;
1502}
1503
1506{
1507 QWidget* w = parentWidget();
1508
1509 bool showRubberband = false;
1510 bool showTracker = false;
1511
1512 if ( w && w->isVisible() && m_data->enabled )
1513 {
1514 if ( rubberBand() != NoRubberBand && isActive() &&
1515 rubberBandPen().style() != Qt::NoPen )
1516 {
1517 showRubberband = true;
1518 }
1519
1520 if ( trackerMode() == AlwaysOn ||
1521 ( trackerMode() == ActiveOnly && isActive() ) )
1522 {
1523 if ( trackerPen() != Qt::NoPen
1524 && !trackerRect( QFont() ).isEmpty() )
1525 {
1526 showTracker = true;
1527 }
1528 }
1529 }
1530
1531 QPointer< Rubberband >& rw = m_data->rubberBandOverlay;
1532 if ( showRubberband )
1533 {
1534 if ( rw.isNull() )
1535 {
1536 rw = new Rubberband( this, NULL ); // NULL -> no extra event filter
1537 rw->setObjectName( "PickerRubberBand" );
1538 rw->setParent( w );
1539 rw->resize( w->size() );
1540 }
1541
1542 if ( m_data->rubberBand <= RectRubberBand )
1543 rw->setMaskMode( QwtWidgetOverlay::MaskHint );
1544 else
1545 rw->setMaskMode( QwtWidgetOverlay::AlphaMask );
1546
1547 rw->updateOverlay();
1548 }
1549 else
1550 {
1551 if ( m_data->openGL )
1552 {
1553 // Qt 4.8 crashes for a delete
1554 if ( !rw.isNull() )
1555 {
1556 rw->hide();
1557 rw->deleteLater();
1558 rw = NULL;
1559 }
1560 }
1561 else
1562 {
1563 delete rw;
1564 }
1565 }
1566
1567 QPointer< Tracker >& tw = m_data->trackerOverlay;
1568 if ( showTracker )
1569 {
1570 if ( tw.isNull() )
1571 {
1572 tw = new Tracker( this, NULL ); // NULL -> no extra event filter
1573 tw->setObjectName( "PickerTracker" );
1574 tw->setParent( w );
1575 tw->resize( w->size() );
1576 }
1577 tw->setFont( m_data->trackerFont );
1578 tw->updateOverlay();
1579 }
1580 else
1581 {
1582 if ( m_data->openGL )
1583 {
1584 // Qt 4.8 crashes for a delete
1585 if ( !tw.isNull() )
1586 {
1587 tw->hide();
1588 tw->deleteLater();
1589 tw = NULL;
1590 }
1591 }
1592 else
1593 {
1594 delete tw;
1595 }
1596 }
1597}
1598
1601{
1602 return m_data->rubberBandOverlay;
1603}
1604
1607{
1608 return m_data->trackerOverlay;
1609}
1610
1611#include "moc_qwt_picker.cpp"
bool keyMatch(KeyPatternCode, const QKeyEvent *) const
Compare a key event with an event pattern.
@ KeyDown
Qt::Key_Down.
@ KeyAbort
Qt::Key_Escape.
@ KeyRight
Qt::Key_Right.
@ KeyLeft
Qt::Key_Left.
static void drawEllipse(QPainter *, const QRectF &)
Wrapper for QPainter::drawEllipse()
static void drawRect(QPainter *, qreal x, qreal y, qreal w, qreal h)
Wrapper for QPainter::drawRect()
static qreal devicePixelRatio(const QPaintDevice *)
static void drawLine(QPainter *, qreal x1, qreal y1, qreal x2, qreal y2)
Wrapper for QPainter::drawLine()
QwtPicker provides selections on a widget.
Definition qwt_picker.h:104
DisplayMode
Display mode.
Definition qwt_picker.h:162
@ AlwaysOn
Display always.
Definition qwt_picker.h:167
@ AlwaysOff
Display never.
Definition qwt_picker.h:164
@ ActiveOnly
Display only when the selection is active.
Definition qwt_picker.h:170
virtual void updateDisplay()
Update the state of rubber band and tracker label.
QFont trackerFont() const
ResizeMode resizeMode() const
virtual void reset()
virtual void drawRubberBand(QPainter *) const
RubberBand rubberBand() const
void setRubberBandPen(const QPen &)
virtual QRegion trackerMask() const
virtual void remove()
virtual void stretchSelection(const QSize &oldSize, const QSize &newSize)
virtual bool eventFilter(QObject *, QEvent *) override
Event filter.
void selected(const QPolygon &polygon)
QPen rubberBandPen() const
const QwtWidgetOverlay * rubberBandOverlay() const
virtual void begin()
virtual void widgetMousePressEvent(QMouseEvent *)
virtual void move(const QPoint &)
virtual ~QwtPicker()
Destructor.
virtual void append(const QPoint &)
void setStateMachine(QwtPickerMachine *)
virtual void drawTracker(QPainter *) const
QPen trackerPen() const
virtual QRegion rubberBandMask() const
QPoint trackerPosition() const
virtual void widgetEnterEvent(QEvent *)
void setRubberBand(RubberBand)
const QwtWidgetOverlay * trackerOverlay() const
virtual void widgetMouseMoveEvent(QMouseEvent *)
void activated(bool on)
virtual void widgetLeaveEvent(QEvent *)
virtual void transition(const QEvent *)
virtual bool accept(QPolygon &) const
Validate and fix up the selection.
void setTrackerMode(DisplayMode)
Set the display mode of the tracker.
virtual QPainterPath pickArea() const
bool isActive() const
virtual void widgetKeyReleaseEvent(QKeyEvent *)
void setTrackerFont(const QFont &)
void setEnabled(bool)
En/disable the picker.
bool isEnabled() const
DisplayMode trackerMode() const
virtual QPolygon adjustedPoints(const QPolygon &) const
Map the pickedPoints() into a selection()
@ VLineRubberBand
A vertical line ( only for QwtPickerMachine::PointSelection )
Definition qwt_picker.h:136
@ CrossRubberBand
A crosshair ( only for QwtPickerMachine::PointSelection )
Definition qwt_picker.h:139
@ EllipseRubberBand
An ellipse ( only for QwtPickerMachine::RectSelection )
Definition qwt_picker.h:145
@ PolygonRubberBand
A polygon ( only for QwtPickerMachine::PolygonSelection )
Definition qwt_picker.h:148
@ HLineRubberBand
A horizontal line ( only for QwtPickerMachine::PointSelection )
Definition qwt_picker.h:133
@ NoRubberBand
No rubberband.
Definition qwt_picker.h:130
@ RectRubberBand
A rectangle ( only for QwtPickerMachine::RectSelection )
Definition qwt_picker.h:142
@ Stretch
All points are scaled according to the new size,.
Definition qwt_picker.h:184
virtual QwtText trackerText(const QPoint &pos) const
Return the label for a position.
virtual void widgetMouseReleaseEvent(QMouseEvent *)
virtual bool end(bool ok=true)
Close a selection setting the state to inactive.
void appended(const QPoint &pos)
QWidget * parentWidget()
Return the parent widget, where the selection happens.
void moved(const QPoint &pos)
const QPolygon & pickedPoints() const
const QwtPickerMachine * stateMachine() const
void removed(const QPoint &pos)
void changed(const QPolygon &selection)
virtual QRect trackerRect(const QFont &) const
virtual void widgetMouseDoubleClickEvent(QMouseEvent *)
virtual void widgetKeyPressEvent(QKeyEvent *)
void setTrackerPen(const QPen &)
void setResizeMode(ResizeMode)
Set the resize mode.
virtual void widgetWheelEvent(QWheelEvent *)
QwtPicker(QWidget *parent)
QPolygon selection() const
A state machine for QwtPicker selections.
@ NoSelection
The state machine not usable for any type of selection.
@ RectSelection
The state machine is for selecting a rectangle (2 points).
@ PolygonSelection
The state machine is for selecting a polygon (many points).
@ PointSelection
The state machine is for selecting a single point.
SelectionType selectionType() const
Return the selection type.
virtual QList< Command > transition(const QwtEventPattern &, const QEvent *)=0
Transition.
void reset()
Set the current state to 0.
A class representing a text.
Definition qwt_text.h:52
QSizeF textSize() const
Definition qwt_text.cpp:570
bool isEmpty() const
Definition qwt_text.cpp:739
void draw(QPainter *painter, const QRectF &rect) const
Definition qwt_text.cpp:615
An overlay for a widget.
@ AlphaMask
Calculate a mask by checking the alpha values.
@ MaskHint
Use maskHint() as mask.