source: ntrip/trunk/BNC/qwt/qwt_panner.cpp@ 10006

Last change on this file since 10006 was 9383, checked in by stoecker, 4 years ago

update to qwt verion 6.1.1 to fix build with newer Qt5

File size: 12.3 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
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_panner.h"
11#include "qwt_picker.h"
12#include "qwt_painter.h"
13#include <qpainter.h>
14#include <qpixmap.h>
15#include <qevent.h>
16#include <qcursor.h>
17#include <qbitmap.h>
18
19static QVector<QwtPicker *> qwtActivePickers( QWidget *w )
20{
21 QVector<QwtPicker *> pickers;
22
23 QObjectList children = w->children();
24 for ( int i = 0; i < children.size(); i++ )
25 {
26 QwtPicker *picker = qobject_cast<QwtPicker *>( children[i] );
27 if ( picker && picker->isEnabled() )
28 pickers += picker;
29 }
30
31 return pickers;
32}
33
34class QwtPanner::PrivateData
35{
36public:
37 PrivateData():
38 button( Qt::LeftButton ),
39 buttonModifiers( Qt::NoModifier ),
40 abortKey( Qt::Key_Escape ),
41 abortKeyModifiers( Qt::NoModifier ),
42#ifndef QT_NO_CURSOR
43 cursor( NULL ),
44 restoreCursor( NULL ),
45 hasCursor( false ),
46#endif
47 isEnabled( false )
48 {
49 orientations = Qt::Vertical | Qt::Horizontal;
50 }
51
52 ~PrivateData()
53 {
54#ifndef QT_NO_CURSOR
55 delete cursor;
56 delete restoreCursor;
57#endif
58 }
59
60 Qt::MouseButton button;
61 Qt::KeyboardModifiers buttonModifiers;
62
63 int abortKey;
64 Qt::KeyboardModifiers abortKeyModifiers;
65
66 QPoint initialPos;
67 QPoint pos;
68
69 QPixmap pixmap;
70 QBitmap contentsMask;
71
72#ifndef QT_NO_CURSOR
73 QCursor *cursor;
74 QCursor *restoreCursor;
75 bool hasCursor;
76#endif
77 bool isEnabled;
78 Qt::Orientations orientations;
79};
80
81/*!
82 Creates an panner that is enabled for the left mouse button.
83
84 \param parent Parent widget to be panned
85*/
86QwtPanner::QwtPanner( QWidget *parent ):
87 QWidget( parent )
88{
89 d_data = new PrivateData();
90
91 setAttribute( Qt::WA_TransparentForMouseEvents );
92 setAttribute( Qt::WA_NoSystemBackground );
93 setFocusPolicy( Qt::NoFocus );
94 hide();
95
96 setEnabled( true );
97}
98
99//! Destructor
100QwtPanner::~QwtPanner()
101{
102 delete d_data;
103}
104
105/*!
106 Change the mouse button and modifiers used for panning
107 The defaults are Qt::LeftButton and Qt::NoModifier
108*/
109void QwtPanner::setMouseButton( Qt::MouseButton button,
110 Qt::KeyboardModifiers modifiers )
111{
112 d_data->button = button;
113 d_data->buttonModifiers = modifiers;
114}
115
116//! Get mouse button and modifiers used for panning
117void QwtPanner::getMouseButton( Qt::MouseButton &button,
118 Qt::KeyboardModifiers &modifiers ) const
119{
120 button = d_data->button;
121 modifiers = d_data->buttonModifiers;
122}
123
124/*!
125 Change the abort key
126 The defaults are Qt::Key_Escape and Qt::NoModifiers
127
128 \param key Key ( See Qt::Keycode )
129 \param modifiers Keyboard modifiers
130*/
131void QwtPanner::setAbortKey( int key,
132 Qt::KeyboardModifiers modifiers )
133{
134 d_data->abortKey = key;
135 d_data->abortKeyModifiers = modifiers;
136}
137
138//! Get the abort key and modifiers
139void QwtPanner::getAbortKey( int &key,
140 Qt::KeyboardModifiers &modifiers ) const
141{
142 key = d_data->abortKey;
143 modifiers = d_data->abortKeyModifiers;
144}
145
146/*!
147 Change the cursor, that is active while panning
148 The default is the cursor of the parent widget.
149
150 \param cursor New cursor
151
152 \sa setCursor()
153*/
154#ifndef QT_NO_CURSOR
155void QwtPanner::setCursor( const QCursor &cursor )
156{
157 d_data->cursor = new QCursor( cursor );
158}
159#endif
160
161/*!
162 \return Cursor that is active while panning
163 \sa setCursor()
164*/
165#ifndef QT_NO_CURSOR
166const QCursor QwtPanner::cursor() const
167{
168 if ( d_data->cursor )
169 return *d_data->cursor;
170
171 if ( parentWidget() )
172 return parentWidget()->cursor();
173
174 return QCursor();
175}
176#endif
177
178/*!
179 \brief En/disable the panner
180
181 When enabled is true an event filter is installed for
182 the observed widget, otherwise the event filter is removed.
183
184 \param on true or false
185 \sa isEnabled(), eventFilter()
186*/
187void QwtPanner::setEnabled( bool on )
188{
189 if ( d_data->isEnabled != on )
190 {
191 d_data->isEnabled = on;
192
193 QWidget *w = parentWidget();
194 if ( w )
195 {
196 if ( d_data->isEnabled )
197 {
198 w->installEventFilter( this );
199 }
200 else
201 {
202 w->removeEventFilter( this );
203 hide();
204 }
205 }
206 }
207}
208
209/*!
210 Set the orientations, where panning is enabled
211 The default value is in both directions: Qt::Horizontal | Qt::Vertical
212
213 /param o Orientation
214*/
215void QwtPanner::setOrientations( Qt::Orientations o )
216{
217 d_data->orientations = o;
218}
219
220//! Return the orientation, where paning is enabled
221Qt::Orientations QwtPanner::orientations() const
222{
223 return d_data->orientations;
224}
225
226/*!
227 \return True if an orientation is enabled
228 \sa orientations(), setOrientations()
229*/
230bool QwtPanner::isOrientationEnabled( Qt::Orientation o ) const
231{
232 return d_data->orientations & o;
233}
234
235/*!
236 \return true when enabled, false otherwise
237 \sa setEnabled, eventFilter()
238*/
239bool QwtPanner::isEnabled() const
240{
241 return d_data->isEnabled;
242}
243
244/*!
245 \brief Paint event
246
247 Repaint the grabbed pixmap on its current position and
248 fill the empty spaces by the background of the parent widget.
249
250 \param event Paint event
251*/
252void QwtPanner::paintEvent( QPaintEvent *event )
253{
254 int dx = d_data->pos.x() - d_data->initialPos.x();
255 int dy = d_data->pos.y() - d_data->initialPos.y();
256
257 QRectF r;
258 r.setSize( d_data->pixmap.size() );
259#if QT_VERSION >= 0x050000
260 r.setSize( r.size() / d_data->pixmap.devicePixelRatio() );
261#endif
262 r.moveCenter( QPointF( r.center().x() + dx, r.center().y() + dy ) );
263
264 QPixmap pm = QwtPainter::backingStore( this, size() );
265 QwtPainter::fillPixmap( parentWidget(), pm );
266
267 QPainter painter( &pm );
268
269 if ( !d_data->contentsMask.isNull() )
270 {
271 QPixmap masked = d_data->pixmap;
272 masked.setMask( d_data->contentsMask );
273 painter.drawPixmap( r.toRect(), masked );
274 }
275 else
276 {
277 painter.drawPixmap( r.toRect(), d_data->pixmap );
278 }
279
280 painter.end();
281
282 if ( !d_data->contentsMask.isNull() )
283 pm.setMask( d_data->contentsMask );
284
285 painter.begin( this );
286 painter.setClipRegion( event->region() );
287 painter.drawPixmap( 0, 0, pm );
288}
289
290/*!
291 \brief Calculate a mask for the contents of the panned widget
292
293 Sometimes only parts of the contents of a widget should be
294 panned. F.e. for a widget with a styled background with rounded borders
295 only the area inside of the border should be panned.
296
297 \return An empty bitmap, indicating no mask
298*/
299QBitmap QwtPanner::contentsMask() const
300{
301 return QBitmap();
302}
303
304/*!
305 Grab the widget into a pixmap.
306 \return Grabbed pixmap
307*/
308QPixmap QwtPanner::grab() const
309{
310#if QT_VERSION >= 0x050000
311 return parentWidget()->grab( parentWidget()->rect() );
312#else
313 return QPixmap::grabWidget( parentWidget() );
314#endif
315}
316
317/*!
318 \brief Event filter
319
320 When isEnabled() is true mouse events of the
321 observed widget are filtered.
322
323 \param object Object to be filtered
324 \param event Event
325
326 \return Always false, beside for paint events for the
327 parent widget.
328
329 \sa widgetMousePressEvent(), widgetMouseReleaseEvent(),
330 widgetMouseMoveEvent()
331*/
332bool QwtPanner::eventFilter( QObject *object, QEvent *event )
333{
334 if ( object == NULL || object != parentWidget() )
335 return false;
336
337 switch ( event->type() )
338 {
339 case QEvent::MouseButtonPress:
340 {
341 widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
342 break;
343 }
344 case QEvent::MouseMove:
345 {
346 widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
347 break;
348 }
349 case QEvent::MouseButtonRelease:
350 {
351 widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
352 break;
353 }
354 case QEvent::KeyPress:
355 {
356 widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
357 break;
358 }
359 case QEvent::KeyRelease:
360 {
361 widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
362 break;
363 }
364 case QEvent::Paint:
365 {
366 if ( isVisible() )
367 return true;
368 break;
369 }
370 default:;
371 }
372
373 return false;
374}
375
376/*!
377 Handle a mouse press event for the observed widget.
378
379 \param mouseEvent Mouse event
380 \sa eventFilter(), widgetMouseReleaseEvent(),
381 widgetMouseMoveEvent(),
382*/
383void QwtPanner::widgetMousePressEvent( QMouseEvent *mouseEvent )
384{
385 if ( ( mouseEvent->button() != d_data->button )
386 || ( mouseEvent->modifiers() != d_data->buttonModifiers ) )
387 {
388 return;
389 }
390
391 QWidget *w = parentWidget();
392 if ( w == NULL )
393 return;
394
395#ifndef QT_NO_CURSOR
396 showCursor( true );
397#endif
398
399 d_data->initialPos = d_data->pos = mouseEvent->pos();
400
401 setGeometry( parentWidget()->rect() );
402
403 // We don't want to grab the picker !
404 QVector<QwtPicker *> pickers = qwtActivePickers( parentWidget() );
405 for ( int i = 0; i < pickers.size(); i++ )
406 pickers[i]->setEnabled( false );
407
408 d_data->pixmap = grab();
409 d_data->contentsMask = contentsMask();
410
411 for ( int i = 0; i < pickers.size(); i++ )
412 pickers[i]->setEnabled( true );
413
414 show();
415}
416
417/*!
418 Handle a mouse move event for the observed widget.
419
420 \param mouseEvent Mouse event
421 \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent()
422*/
423void QwtPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
424{
425 if ( !isVisible() )
426 return;
427
428 QPoint pos = mouseEvent->pos();
429 if ( !isOrientationEnabled( Qt::Horizontal ) )
430 pos.setX( d_data->initialPos.x() );
431 if ( !isOrientationEnabled( Qt::Vertical ) )
432 pos.setY( d_data->initialPos.y() );
433
434 if ( pos != d_data->pos && rect().contains( pos ) )
435 {
436 d_data->pos = pos;
437 update();
438
439 Q_EMIT moved( d_data->pos.x() - d_data->initialPos.x(),
440 d_data->pos.y() - d_data->initialPos.y() );
441 }
442}
443
444/*!
445 Handle a mouse release event for the observed widget.
446
447 \param mouseEvent Mouse event
448 \sa eventFilter(), widgetMousePressEvent(),
449 widgetMouseMoveEvent(),
450*/
451void QwtPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
452{
453 if ( isVisible() )
454 {
455 hide();
456#ifndef QT_NO_CURSOR
457 showCursor( false );
458#endif
459
460 QPoint pos = mouseEvent->pos();
461 if ( !isOrientationEnabled( Qt::Horizontal ) )
462 pos.setX( d_data->initialPos.x() );
463 if ( !isOrientationEnabled( Qt::Vertical ) )
464 pos.setY( d_data->initialPos.y() );
465
466 d_data->pixmap = QPixmap();
467 d_data->contentsMask = QBitmap();
468 d_data->pos = pos;
469
470 if ( d_data->pos != d_data->initialPos )
471 {
472 Q_EMIT panned( d_data->pos.x() - d_data->initialPos.x(),
473 d_data->pos.y() - d_data->initialPos.y() );
474 }
475 }
476}
477
478/*!
479 Handle a key press event for the observed widget.
480
481 \param keyEvent Key event
482 \sa eventFilter(), widgetKeyReleaseEvent()
483*/
484void QwtPanner::widgetKeyPressEvent( QKeyEvent *keyEvent )
485{
486 if ( ( keyEvent->key() == d_data->abortKey )
487 && ( keyEvent->modifiers() == d_data->abortKeyModifiers ) )
488 {
489 hide();
490
491#ifndef QT_NO_CURSOR
492 showCursor( false );
493#endif
494 d_data->pixmap = QPixmap();
495 }
496}
497
498/*!
499 Handle a key release event for the observed widget.
500
501 \param keyEvent Key event
502 \sa eventFilter(), widgetKeyReleaseEvent()
503*/
504void QwtPanner::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
505{
506 Q_UNUSED( keyEvent );
507}
508
509#ifndef QT_NO_CURSOR
510void QwtPanner::showCursor( bool on )
511{
512 if ( on == d_data->hasCursor )
513 return;
514
515 QWidget *w = parentWidget();
516 if ( w == NULL || d_data->cursor == NULL )
517 return;
518
519 d_data->hasCursor = on;
520
521 if ( on )
522 {
523 if ( w->testAttribute( Qt::WA_SetCursor ) )
524 {
525 delete d_data->restoreCursor;
526 d_data->restoreCursor = new QCursor( w->cursor() );
527 }
528 w->setCursor( *d_data->cursor );
529 }
530 else
531 {
532 if ( d_data->restoreCursor )
533 {
534 w->setCursor( *d_data->restoreCursor );
535 delete d_data->restoreCursor;
536 d_data->restoreCursor = NULL;
537 }
538 else
539 w->unsetCursor();
540 }
541}
542#endif
Note: See TracBrowser for help on using the repository browser.