/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ // vim: expandtab #include #include #include #include #include #if QT_VERSION < 0x040000 #include #endif #include "qwt_picker.h" #include "qwt_array.h" #include "qwt_panner.h" static QwtArray activePickers(QWidget *w) { QwtArray pickers; #if QT_VERSION >= 0x040000 QObjectList children = w->children(); for ( int i = 0; i < children.size(); i++ ) { QObject *obj = children[i]; if ( obj->inherits("QwtPicker") ) { QwtPicker *picker = (QwtPicker *)obj; if ( picker->isEnabled() ) pickers += picker; } } #else QObjectList *children = (QObjectList *)w->children(); if ( children ) { for ( QObjectListIterator it(*children); it.current(); ++it ) { QObject *obj = (QObject *)it.current(); if ( obj->inherits("QwtPicker") ) { QwtPicker *picker = (QwtPicker *)obj; if ( picker->isEnabled() ) { pickers.resize(pickers.size() + 1); pickers[int(pickers.size()) - 1] = picker; } } } } #endif return pickers; } class QwtPanner::PrivateData { public: PrivateData(): button(Qt::LeftButton), buttonState(Qt::NoButton), abortKey(Qt::Key_Escape), abortKeyState(Qt::NoButton), #ifndef QT_NO_CURSOR cursor(NULL), restoreCursor(NULL), hasCursor(false), #endif isEnabled(false) { #if QT_VERSION >= 0x040000 orientations = Qt::Vertical | Qt::Horizontal; #else orientations[Qt::Vertical] = true; orientations[Qt::Horizontal] = true; #endif } ~PrivateData() { #ifndef QT_NO_CURSOR delete cursor; delete restoreCursor; #endif } int button; int buttonState; int abortKey; int abortKeyState; QPoint initialPos; QPoint pos; QPixmap pixmap; #ifndef QT_NO_CURSOR QCursor *cursor; QCursor *restoreCursor; bool hasCursor; #endif bool isEnabled; #if QT_VERSION >= 0x040000 Qt::Orientations orientations; #else bool orientations[2]; #endif }; /*! Creates an panner that is enabled for the left mouse button. \param parent Parent widget to be panned */ QwtPanner::QwtPanner(QWidget *parent): QWidget(parent) { d_data = new PrivateData(); #if QT_VERSION >= 0x040000 setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_NoSystemBackground); setFocusPolicy(Qt::NoFocus); #else setBackgroundMode(Qt::NoBackground); setFocusPolicy(QWidget::NoFocus); #endif hide(); setEnabled(true); } //! Destructor QwtPanner::~QwtPanner() { delete d_data; } /*! Change the mouse button The defaults are Qt::LeftButton and Qt::NoButton */ void QwtPanner::setMouseButton(int button, int buttonState) { d_data->button = button; d_data->buttonState = buttonState; } //! Get the mouse button void QwtPanner::getMouseButton(int &button, int &buttonState) const { button = d_data->button; buttonState = d_data->buttonState; } /*! Change the abort key The defaults are Qt::Key_Escape and Qt::NoButton */ void QwtPanner::setAbortKey(int key, int state) { d_data->abortKey = key; d_data->abortKeyState = state; } //! Get the abort key void QwtPanner::getAbortKey(int &key, int &state) const { key = d_data->abortKey; state = d_data->abortKeyState; } /*! Change the cursor, that is active while panning The default is the cursor of the parent widget. \param cursor New cursor \sa setCursor() */ #ifndef QT_NO_CURSOR void QwtPanner::setCursor(const QCursor &cursor) { d_data->cursor = new QCursor(cursor); } #endif /*! \return Cursor that is active while panning \sa setCursor() */ #ifndef QT_NO_CURSOR const QCursor QwtPanner::cursor() const { if ( d_data->cursor ) return *d_data->cursor; if ( parentWidget() ) return parentWidget()->cursor(); return QCursor(); } #endif /*! \brief En/disable the panner When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter() */ void QwtPanner::setEnabled(bool on) { if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QWidget *w = parentWidget(); if ( w ) { if ( d_data->isEnabled ) { w->installEventFilter(this); } else { w->removeEventFilter(this); hide(); } } } } #if QT_VERSION >= 0x040000 /*! Set the orientations, where panning is enabled The default value is in both directions: Qt::Horizontal | Qt::Vertical /param o Orientation */ void QwtPanner::setOrientations(Qt::Orientations o) { d_data->orientations = o; } //! Return the orientation, where paning is enabled Qt::Orientations QwtPanner::orientations() const { return d_data->orientations; } #else void QwtPanner::enableOrientation(Qt::Orientation o, bool enable) { if ( o == Qt::Vertical || o == Qt::Horizontal ) d_data->orientations[o] = enable; } #endif /*! Return true if a orientatio is enabled \sa orientations(), setOrientations() */ bool QwtPanner::isOrientationEnabled(Qt::Orientation o) const { #if QT_VERSION >= 0x040000 return d_data->orientations & o; #else if ( o == Qt::Vertical || o == Qt::Horizontal ) return d_data->orientations[o]; return false; #endif } /*! \return true when enabled, false otherwise \sa setEnabled, eventFilter() */ bool QwtPanner::isEnabled() const { return d_data->isEnabled; } /*! \brief Paint event Repaint the grabbed pixmap on its current position and fill the empty spaces by the background of the parent widget. \param pe Paint event */ void QwtPanner::paintEvent(QPaintEvent *pe) { QPixmap pm(size()); QPainter painter(&pm); const QColor bg = #if QT_VERSION < 0x040000 parentWidget()->palette().color( QPalette::Normal, QColorGroup::Background); #else parentWidget()->palette().color( QPalette::Normal, QPalette::Background); #endif painter.setPen(Qt::NoPen); painter.setBrush(QBrush(bg)); painter.drawRect(0, 0, pm.width(), pm.height()); int dx = d_data->pos.x() - d_data->initialPos.x(); int dy = d_data->pos.y() - d_data->initialPos.y(); QRect r(0, 0, d_data->pixmap.width(), d_data->pixmap.height()); r.moveCenter(QPoint(r.center().x() + dx, r.center().y() + dy)); painter.drawPixmap(r, d_data->pixmap); painter.end(); painter.begin(this); painter.setClipRegion(pe->region()); painter.drawPixmap(0, 0, pm); } /*! \brief Event filter When isEnabled() the mouse events of the observed widget are filtered. \sa widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent() */ bool QwtPanner::eventFilter(QObject *o, QEvent *e) { if ( o == NULL || o != parentWidget() ) return false; switch(e->type()) { case QEvent::MouseButtonPress: { widgetMousePressEvent((QMouseEvent *)e); break; } case QEvent::MouseMove: { widgetMouseMoveEvent((QMouseEvent *)e); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent((QMouseEvent *)e); break; } case QEvent::KeyPress: { widgetKeyPressEvent((QKeyEvent *)e); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent((QKeyEvent *)e); break; } case QEvent::Paint: { if ( isVisible() ) return true; break; } default: ; } return false; } /*! Handle a mouse press event for the observed widget. \param me Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), */ void QwtPanner::widgetMousePressEvent(QMouseEvent *me) { if ( me->button() != d_data->button ) return; QWidget *w = parentWidget(); if ( w == NULL ) return; #if QT_VERSION < 0x040000 if ( (me->state() & Qt::KeyButtonMask) != (d_data->buttonState & Qt::KeyButtonMask) ) #else if ( (me->modifiers() & Qt::KeyboardModifierMask) != (int)(d_data->buttonState & Qt::KeyboardModifierMask) ) #endif { return; } #ifndef QT_NO_CURSOR showCursor(true); #endif d_data->initialPos = d_data->pos = me->pos(); QRect cr = parentWidget()->rect(); if ( parentWidget()->inherits("QFrame") ) { const QFrame* frame = (QFrame*)parentWidget(); cr = frame->contentsRect(); } setGeometry(cr); // We don't want to grab the picker ! QwtArray pickers = activePickers(parentWidget()); for ( int i = 0; i < (int)pickers.size(); i++ ) pickers[i]->setEnabled(false); d_data->pixmap = QPixmap::grabWidget(parentWidget(), cr.x(), cr.y(), cr.width(), cr.height()); for ( int i = 0; i < (int)pickers.size(); i++ ) pickers[i]->setEnabled(true); show(); } /*! Handle a mouse move event for the observed widget. \param me Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent() */ void QwtPanner::widgetMouseMoveEvent(QMouseEvent *me) { if ( !isVisible() ) return; QPoint pos = me->pos(); if ( !isOrientationEnabled(Qt::Horizontal) ) pos.setX(d_data->initialPos.x()); if ( !isOrientationEnabled(Qt::Vertical) ) pos.setY(d_data->initialPos.y()); if ( pos != d_data->pos && rect().contains(pos) ) { d_data->pos = pos; update(); emit moved(d_data->pos.x() - d_data->initialPos.x(), d_data->pos.y() - d_data->initialPos.y()); } } /*! Handle a mouse release event for the observed widget. \param me Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(), */ void QwtPanner::widgetMouseReleaseEvent(QMouseEvent *me) { if ( isVisible() ) { hide(); #ifndef QT_NO_CURSOR showCursor(false); #endif QPoint pos = me->pos(); if ( !isOrientationEnabled(Qt::Horizontal) ) pos.setX(d_data->initialPos.x()); if ( !isOrientationEnabled(Qt::Vertical) ) pos.setY(d_data->initialPos.y()); d_data->pixmap = QPixmap(); d_data->pos = pos; if ( d_data->pos != d_data->initialPos ) { emit panned(d_data->pos.x() - d_data->initialPos.x(), d_data->pos.y() - d_data->initialPos.y()); } } } /*! Handle a key press event for the observed widget. \param ke Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtPanner::widgetKeyPressEvent(QKeyEvent *ke) { if ( ke->key() == d_data->abortKey ) { const bool matched = #if QT_VERSION < 0x040000 (ke->state() & Qt::KeyButtonMask) == (d_data->abortKeyState & Qt::KeyButtonMask); #else (ke->modifiers() & Qt::KeyboardModifierMask) == (int)(d_data->abortKeyState & Qt::KeyboardModifierMask); #endif if ( matched ) { hide(); #ifndef QT_NO_CURSOR showCursor(false); #endif d_data->pixmap = QPixmap(); } } } /*! Handle a key release event for the observed widget. \param ke Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtPanner::widgetKeyReleaseEvent(QKeyEvent *) { } #ifndef QT_NO_CURSOR void QwtPanner::showCursor(bool on) { if ( on == d_data->hasCursor ) return; QWidget *w = parentWidget(); if ( w == NULL || d_data->cursor == NULL ) return; d_data->hasCursor = on; if ( on ) { #if QT_VERSION < 0x040000 if ( w->testWState(WState_OwnCursor) ) #else if ( w->testAttribute(Qt::WA_SetCursor) ) #endif { delete d_data->restoreCursor; d_data->restoreCursor = new QCursor(w->cursor()); } w->setCursor(*d_data->cursor); } else { if ( d_data->restoreCursor ) { w->setCursor(*d_data->restoreCursor); delete d_data->restoreCursor; d_data->restoreCursor = NULL; } else w->unsetCursor(); } } #endif