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

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