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

Last change on this file since 8804 was 8127, checked in by stoecker, 8 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 12.1 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 pe Paint event
251*/
252void QwtPanner::paintEvent( QPaintEvent *pe )
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 QRect r( 0, 0, d_data->pixmap.width(), d_data->pixmap.height() );
258 r.moveCenter( QPoint( r.center().x() + dx, r.center().y() + dy ) );
259
260 QPixmap pm( size() );
261 QwtPainter::fillPixmap( parentWidget(), pm );
262
263 QPainter painter( &pm );
264
265 if ( !d_data->contentsMask.isNull() )
266 {
267 QPixmap masked = d_data->pixmap;
268 masked.setMask( d_data->contentsMask );
269 painter.drawPixmap( r, masked );
270 }
271 else
272 {
273 painter.drawPixmap( r, d_data->pixmap );
274 }
275
276 painter.end();
277
278 if ( !d_data->contentsMask.isNull() )
279 pm.setMask( d_data->contentsMask );
280
281 painter.begin( this );
282 painter.setClipRegion( pe->region() );
283 painter.drawPixmap( 0, 0, pm );
284}
285
286/*!
287 \brief Calculate a mask for the contents of the panned widget
288
289 Sometimes only parts of the contents of a widget should be
290 panned. F.e. for a widget with a styled background with rounded borders
291 only the area inside of the border should be panned.
292
293 \return An empty bitmap, indicating no mask
294*/
295QBitmap QwtPanner::contentsMask() const
296{
297 return QBitmap();
298}
299
300/*!
301 Grab the widget into a pixmap.
302 \return Grabbed pixmap
303*/
304QPixmap QwtPanner::grab() const
305{
306#if QT_VERSION >= 0x050000
307 return parentWidget()->grab( parentWidget()->rect() );
308#else
309 return QPixmap::grabWidget( parentWidget() );
310#endif
311}
312
313/*!
314 \brief Event filter
315
316 When isEnabled() is true mouse events of the
317 observed widget are filtered.
318
319 \param object Object to be filtered
320 \param event Event
321
322 \return Always false, beside for paint events for the
323 parent widget.
324
325 \sa widgetMousePressEvent(), widgetMouseReleaseEvent(),
326 widgetMouseMoveEvent()
327*/
328bool QwtPanner::eventFilter( QObject *object, QEvent *event )
329{
330 if ( object == NULL || object != parentWidget() )
331 return false;
332
333 switch ( event->type() )
334 {
335 case QEvent::MouseButtonPress:
336 {
337 widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
338 break;
339 }
340 case QEvent::MouseMove:
341 {
342 widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
343 break;
344 }
345 case QEvent::MouseButtonRelease:
346 {
347 widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
348 break;
349 }
350 case QEvent::KeyPress:
351 {
352 widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
353 break;
354 }
355 case QEvent::KeyRelease:
356 {
357 widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
358 break;
359 }
360 case QEvent::Paint:
361 {
362 if ( isVisible() )
363 return true;
364 break;
365 }
366 default:;
367 }
368
369 return false;
370}
371
372/*!
373 Handle a mouse press event for the observed widget.
374
375 \param mouseEvent Mouse event
376 \sa eventFilter(), widgetMouseReleaseEvent(),
377 widgetMouseMoveEvent(),
378*/
379void QwtPanner::widgetMousePressEvent( QMouseEvent *mouseEvent )
380{
381 if ( ( mouseEvent->button() != d_data->button )
382 || ( mouseEvent->modifiers() != d_data->buttonModifiers ) )
383 {
384 return;
385 }
386
387 QWidget *w = parentWidget();
388 if ( w == NULL )
389 return;
390
391#ifndef QT_NO_CURSOR
392 showCursor( true );
393#endif
394
395 d_data->initialPos = d_data->pos = mouseEvent->pos();
396
397 setGeometry( parentWidget()->rect() );
398
399 // We don't want to grab the picker !
400 QVector<QwtPicker *> pickers = qwtActivePickers( parentWidget() );
401 for ( int i = 0; i < pickers.size(); i++ )
402 pickers[i]->setEnabled( false );
403
404 d_data->pixmap = grab();
405 d_data->contentsMask = contentsMask();
406
407 for ( int i = 0; i < pickers.size(); i++ )
408 pickers[i]->setEnabled( true );
409
410 show();
411}
412
413/*!
414 Handle a mouse move event for the observed widget.
415
416 \param mouseEvent Mouse event
417 \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent()
418*/
419void QwtPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
420{
421 if ( !isVisible() )
422 return;
423
424 QPoint pos = mouseEvent->pos();
425 if ( !isOrientationEnabled( Qt::Horizontal ) )
426 pos.setX( d_data->initialPos.x() );
427 if ( !isOrientationEnabled( Qt::Vertical ) )
428 pos.setY( d_data->initialPos.y() );
429
430 if ( pos != d_data->pos && rect().contains( pos ) )
431 {
432 d_data->pos = pos;
433 update();
434
435 Q_EMIT moved( d_data->pos.x() - d_data->initialPos.x(),
436 d_data->pos.y() - d_data->initialPos.y() );
437 }
438}
439
440/*!
441 Handle a mouse release event for the observed widget.
442
443 \param mouseEvent Mouse event
444 \sa eventFilter(), widgetMousePressEvent(),
445 widgetMouseMoveEvent(),
446*/
447void QwtPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
448{
449 if ( isVisible() )
450 {
451 hide();
452#ifndef QT_NO_CURSOR
453 showCursor( false );
454#endif
455
456 QPoint pos = mouseEvent->pos();
457 if ( !isOrientationEnabled( Qt::Horizontal ) )
458 pos.setX( d_data->initialPos.x() );
459 if ( !isOrientationEnabled( Qt::Vertical ) )
460 pos.setY( d_data->initialPos.y() );
461
462 d_data->pixmap = QPixmap();
463 d_data->contentsMask = QBitmap();
464 d_data->pos = pos;
465
466 if ( d_data->pos != d_data->initialPos )
467 {
468 Q_EMIT panned( d_data->pos.x() - d_data->initialPos.x(),
469 d_data->pos.y() - d_data->initialPos.y() );
470 }
471 }
472}
473
474/*!
475 Handle a key press event for the observed widget.
476
477 \param keyEvent Key event
478 \sa eventFilter(), widgetKeyReleaseEvent()
479*/
480void QwtPanner::widgetKeyPressEvent( QKeyEvent *keyEvent )
481{
482 if ( ( keyEvent->key() == d_data->abortKey )
483 && ( keyEvent->modifiers() == d_data->abortKeyModifiers ) )
484 {
485 hide();
486
487#ifndef QT_NO_CURSOR
488 showCursor( false );
489#endif
490 d_data->pixmap = QPixmap();
491 }
492}
493
494/*!
495 Handle a key release event for the observed widget.
496
497 \param keyEvent Key event
498 \sa eventFilter(), widgetKeyReleaseEvent()
499*/
500void QwtPanner::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
501{
502 Q_UNUSED( keyEvent );
503}
504
505#ifndef QT_NO_CURSOR
506void QwtPanner::showCursor( bool on )
507{
508 if ( on == d_data->hasCursor )
509 return;
510
511 QWidget *w = parentWidget();
512 if ( w == NULL || d_data->cursor == NULL )
513 return;
514
515 d_data->hasCursor = on;
516
517 if ( on )
518 {
519 if ( w->testAttribute( Qt::WA_SetCursor ) )
520 {
521 delete d_data->restoreCursor;
522 d_data->restoreCursor = new QCursor( w->cursor() );
523 }
524 w->setCursor( *d_data->cursor );
525 }
526 else
527 {
528 if ( d_data->restoreCursor )
529 {
530 w->setCursor( *d_data->restoreCursor );
531 delete d_data->restoreCursor;
532 d_data->restoreCursor = NULL;
533 }
534 else
535 w->unsetCursor();
536 }
537}
538#endif
Note: See TracBrowser for help on using the repository browser.