/** ** ** @RDE_HEADER@ ** Event Dispatcher for Qt5 to handle mouse and keyboard event ** $Id$ ** $HeadURL$ ** $Author$ ** ** ----------------------------------------------------------------------------------------------- ** ** Hardware-Environment: Intel-PC ** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5 ** ** Language ........: C++ 11 ** ** ----------------------------------------------------------------------------------------------- ** ** Author ...........: Jörg Turla, SPD G, Tel. 3132 ** ** ----------------------------------------------------------------------------------------------- ** ** Notes .........: ** ** 28.04.2003, JT : First edition for use with Qt4 in START Feature Editor fee ** 25.03.2015, JT : Refactoring for use with Qt5 ** ** ----------------------------------------------------------------------------------------------- */ #include "event_dispatcher.h" #include "gestures.h" #include #include #include #include #include #include namespace SituationMap { namespace RB { EventDispatcher::EventDispatcher(QWidget * getEventsFrom) : AbstractEventDispatcher(getEventsFrom) , _snapEnabled(false) , _snapRatio(5) , _drawRatio(false) , _doubleClickHandled(false) , _leftPressHandled(false) { } /* EventDispatcher::EventDispatcher */ EventDispatcher::EventDispatcher(QWidget * getEventsFrom, EventActionInterface * eventActions ) : AbstractEventDispatcher(getEventsFrom, eventActions) , _snapEnabled(false) , _snapRatio(5) , _drawRatio(false) , _doubleClickHandled(false) , _leftPressHandled(false) { } /* EventDispatcher::EventDispatcher */ bool EventDispatcher::eventFilterKey( int key, Qt::KeyboardModifiers mod ) { QPoint moveDelta; int multiply ( (mod.testFlag(Qt::KeyboardModifier::ShiftModifier)) ? 10 : 1); bool controlKey( (mod.testFlag(Qt::KeyboardModifier::ControlModifier)) ); switch (key) { case Qt::Key_Delete : return onDoDelete(); break; case Qt::Key_Z : if (controlKey) return onDoUndo(); break; case Qt::Key_Escape : return onDoEscape(); break; case Qt::Key_Return : return onDoEnd(); break; case Qt::Key_Left : moveDelta = QPoint(-1, 0)*multiply; break; case Qt::Key_Right : moveDelta = QPoint( 1, 0)*multiply; break; case Qt::Key_Up : moveDelta = QPoint( 0,-1)*multiply; break; case Qt::Key_Down : moveDelta = QPoint( 0, 1)*multiply; break; default : return false; } /* switch */ if (_getEventsFrom != nullptr) { QPoint cursorPos = _getEventsFrom->mapFromGlobal( QCursor::pos() ); onPress( cursorPos.x(), cursorPos.y(), mod ); cursorPos += moveDelta; onMove ( cursorPos.x(), cursorPos.y(), Qt::MouseButton::LeftButton, mod ); onClick( cursorPos.x(), cursorPos.y(), mod ); QCursor::setPos( _getEventsFrom->mapToGlobal(cursorPos) ); } return true; } /* EventDispatcher::eventFilterKey */ bool EventDispatcher::eventFilterGesture( QGestureEvent * gestureEvent ) { bool handled = false; if (gestureEvent) { const QList & gestureList = gestureEvent->gestures(); for (auto gesture : gestureList) { Qt::GestureType gestureType = gesture->gestureType(); Qt::GestureState gestureState = gesture->state(); QTapGesture * tapGesture = nullptr; QTapAndHoldGesture * tapAndHoldGesture = nullptr; QPanGesture * panGesture = nullptr; QPinchGesture * pinchGesture = nullptr; QSwipeGesture * swipeGesture = nullptr; ApplyGesture * applyGesture = nullptr; QString typeName; QString stateName; switch (gestureType) { case Qt::TapGesture : tapGesture = static_cast(gesture); typeName = QLatin1String("TapGesture"); break; case Qt::TapAndHoldGesture : tapAndHoldGesture = static_cast(gesture); typeName = QLatin1String("TapAndHoldGesture"); break; case Qt::PanGesture : panGesture = static_cast(gesture); typeName = QLatin1String("PanGesture"); break; case Qt::PinchGesture : pinchGesture = static_cast(gesture); typeName = QLatin1String("PinchGesture"); break; case Qt::SwipeGesture : swipeGesture = static_cast(gesture); typeName = QLatin1String("SwipeGesture"); break; default: { if (gestureType == _applyGestureID) { applyGesture = static_cast(gesture); typeName = QLatin1String("ApplyGesture"); } } break; } switch (gestureState) { case Qt::NoGesture : stateName = QLatin1String("NoGesture"); break; case Qt::GestureStarted : stateName = QLatin1String("GestureStarted"); break; case Qt::GestureUpdated : stateName = QLatin1String("GestureUpdated"); break; case Qt::GestureFinished : stateName = QLatin1String("GestureFinished"); break; case Qt::GestureCanceled : stateName = QLatin1String("GestureCanceled"); break; } DEBUG_LOG(_logger) << LOGFUNCTION << " Gesture type=" << typeName << " Gesture state=" << stateName; if (panGesture) { const QPoint & offset = panGesture->offset().toPoint(); const QPoint & hotSpot = _getEventsFrom->mapFromGlobal( panGesture->hotSpot().toPoint() ); switch (gestureState) { case Qt::GestureStarted: { handled = onPress( hotSpot.x(), hotSpot.y(), nullptr ); if (handled) gestureEvent -> accept( panGesture ); } break; case Qt::GestureUpdated: handled = onMove ( hotSpot.x() + offset.x(), hotSpot.y() + offset.y(), Qt::MouseButton::LeftButton, nullptr ); break; case Qt::GestureFinished: // handled = onMove ( hotSpot.x() + offset.x(), hotSpot.y() + offset.y(), Qt::MouseButton::LeftButton, 0 ); handled = onClick( hotSpot.x() + offset.x(), hotSpot.y() + offset.y(), nullptr ); break; case Qt::GestureCanceled: getEventActions()->resetAction( this, 0, 0 ); break; default: break; } } if (applyGesture) { switch (gestureState) { case Qt::GestureStarted : gestureEvent -> accept( applyGesture ); break; case Qt::GestureFinished : { getEventActions()->resetAction( this, qRound(applyGesture->position().x()), qRound(applyGesture->position().y()) ); handled = onDoubleClick( qRound(applyGesture->position().x()), qRound(applyGesture->position().y()), nullptr ); if (handled) { gestureEvent -> accept( applyGesture ); return true; } } break; default : break; } } // currently not used Q_UNUSED(handled); Q_UNUSED(tapGesture); Q_UNUSED(tapAndHoldGesture); Q_UNUSED(pinchGesture); Q_UNUSED(swipeGesture); } } return handled; } /* EventDispatcher::eventFilerGesture */ bool EventDispatcher::eventFilterWheel( QWheelEvent * e ) { const int WHEEL_DELTA = 120; // natural mouse driver constant if (e->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier) && e->buttons().testFlag(Qt::MidButton)) { int newValue = (int)_snapRatio + (e->angleDelta() / WHEEL_DELTA).manhattanLength(); _snapRatio = (newValue < 5) ? 5 : newValue; return onMove( e->x(), e->y(), e->buttons(), e->modifiers() ); } return false; } /* EventDispatcher::eventFilterWheel */ bool EventDispatcher::eventFilter( QObject * watched, QEvent * e ) { // Maybe ??? // qCritical() << " _getEventsFrom = " << _getEventsFrom // << " watched = " << watched // << " e->type() = " << e->type(); // if (watched != _getEventsFrom) // return AbstractEventDispatcher::eventFilter(watched,e); Q_UNUSED(watched); QString debugString(QLatin1String("unhandled event")); if (hasFinished()) return true; // don't accept new events if dispatcher is going to finish if (hasActiveEvent()) return true; // don't accept new events before last event has been handled completly if (e) { bool handled( false ); setActiveEvent( true ); switch( e->type() ) { case QEvent::Enter : { debugString = QLatin1String("enter event"); _getEventsFrom -> setFocus(); _doubleClickHandled = false; _leftPressHandled = false; } break; case QEvent::Leave : _doubleClickHandled = _leftPressHandled = false; break; case QEvent::GraphicsSceneMousePress : break; case QEvent::MouseButtonPress : { debugString = QLatin1String("mouse button press event"); _doubleClickHandled = false; QMouseEvent *mouseEvent = static_cast(e); if (Qt::RightButton == mouseEvent->button()) { handled = onMenuPress( mouseEvent->x() , mouseEvent->y() , mouseEvent->modifiers() ); } if (Qt::LeftButton == mouseEvent->button()) { if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))) { handled = onPress( mouseEvent->x() , mouseEvent->y() , mouseEvent->modifiers() ); if (handled) _leftPressHandled = true; } } if (Qt::MidButton == mouseEvent->button()) { handled = mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier); } } break; case QEvent::TouchBegin: { debugString = QLatin1String("mouse button press event TOUCH"); _doubleClickHandled = false; QTouchEvent *mouseEvent = static_cast(e); if (mouseEvent->touchPoints().size() > 0) { const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0); handled = onPress( tp.pos().x() , tp.pos().y() , mouseEvent->modifiers() ); if (handled) _leftPressHandled = true; } break; } case QEvent::GraphicsSceneMouseDoubleClick : break; case QEvent::MouseButtonDblClick : { debugString = QLatin1String("mouse double click event"); QMouseEvent *mouseEvent = static_cast(e); if (Qt::LeftButton == mouseEvent->button()) { if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))) { onDoubleClick( mouseEvent->x() , mouseEvent->y() , mouseEvent->modifiers() ); _doubleClickHandled = handled = true; } } } break; case QEvent::GraphicsSceneMouseRelease : break; case QEvent::MouseButtonRelease : { if (!_doubleClickHandled) { debugString = QLatin1String("mouse button release event"); QMouseEvent *mouseEvent = static_cast(e); if (Qt::RightButton == mouseEvent->button()) { handled = onMenuClick( mouseEvent->x() , mouseEvent->y() , mouseEvent->modifiers() ); } if (Qt::LeftButton == mouseEvent->button()) { if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))) { // The mouse button press event must had be handled before. If not skip button release ... if (_leftPressHandled) { _leftPressHandled = false; handled = onClick( mouseEvent->x() , mouseEvent->y() , mouseEvent->modifiers() ); } else callEventAction( &EventActionInterface::buttonPositionAction, mouseEvent->x(), mouseEvent->y() ); } } if (Qt::MidButton == mouseEvent->button()) { handled = mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier); } } else _doubleClickHandled = false; } break; case QEvent::TouchEnd: { debugString = QLatin1String("mouse button release event TOUCH"); QTouchEvent *mouseEvent = static_cast(e); // The mouse button press event must had be handled before. If not skip button release ... if (mouseEvent->touchPoints().size() > 0) { const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0); if (_leftPressHandled) { _leftPressHandled = false; handled = onClick( tp.pos().x() , tp.pos().y() , mouseEvent->modifiers() ); } else { callEventAction( &EventActionInterface::buttonPositionAction, tp.pos().x(), tp.pos().y() ); } } break; } case QEvent::GraphicsSceneMouseMove : break; case QEvent::MouseMove : { debugString = QLatin1String("mouse move event"); _doubleClickHandled = false; QMouseEvent *mouseEvent = static_cast(e); if (mouseEvent->buttons() != Qt::MidButton) { if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))) { if (_drawRatio) { if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::AltModifier))) { _drawRatio = false; } } else { if (mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::AltModifier)) { _drawRatio = true; } } handled = onMove( mouseEvent->x() , mouseEvent->y() , mouseEvent->buttons() , mouseEvent->modifiers()); // REGG-5230 - PlanEditor: Position beim Erstellen und Modifizieren // von Elementen wird nicht aktualisiert // Next handler is EventMouseNavigator. ::eventFilter() will handle // QEvent::MouseMove and emit mouseMovedEvent to update PositionStr. // If handled == true, the next handler is NOT called. // So emit here alternatively. if (handled) emit mouseMovedEvent(mouseEvent->pos().x(), mouseEvent->pos().y()); } } } break; case QEvent::TouchUpdate: { debugString = QLatin1String("mouse move event Touch"); _doubleClickHandled = false; QTouchEvent* mouseEvent = static_cast(e); if (mouseEvent->touchPoints().size() > 0) { const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0); handled = onMove( tp.pos().x() , tp.pos().y() , Qt::LeftButton , mouseEvent->modifiers()); } break; } case QEvent::KeyPress : { QKeyEvent *keyEvent = static_cast(e); debugString = QStringLiteral("key press event (%1)").arg(keyEvent->key()); handled = eventFilterKey( keyEvent->key(),keyEvent->modifiers() ); if ((keyEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier)) || (keyEvent->key() == Qt::Key_Control)) { setSnapEnabled( true ); _drawRatio = true; handled = true; } } break; case QEvent::KeyRelease : { debugString = QLatin1String("key release event"); if (_drawRatio) { _drawRatio = false; setSnapEnabled( true ); } // handled = true; } break; case QEvent::Wheel : { debugString = QLatin1String("mouse wheel event"); QWheelEvent *wheelEvent = static_cast(e); if (wheelEvent->modifiers() & (Qt::KeyboardModifier::ShiftModifier | Qt::KeyboardModifier::ControlModifier)) { handled = eventFilterWheel( wheelEvent ); } } break; case QEvent::Gesture: { handled = eventFilterGesture( static_cast(e) ); } break; default: break; } /* switch */ if (!hasFinished()) setActiveEvent( false ); if (handled) e->accept(); TRACE_LOG(_logger) << LOGFUNCTION << " Event " << debugString << " handled = " << handled; if (handled) return true; } return AbstractEventDispatcher::eventFilter(watched,e); } /* EventDispatcher::eventFilter */ bool EventDispatcher::onMove(int x, int y, Qt::MouseButtons buttons, Qt::KeyboardModifiers mod) { Q_UNUSED(mod); if (buttons.testFlag(Qt::MouseButton::LeftButton)) return callEventAction( &EventActionInterface::movePickedAction, x, y ); return callEventAction( &EventActionInterface::moveAction, x, y ); } /* EventDispatcher::onMove */ bool EventDispatcher::onPress(int x, int y, Qt::KeyboardModifiers mod) { if (mod == Qt::NoModifier) return callEventAction( &EventActionInterface::selectAction, x, y ); if (mod.testFlag(Qt::KeyboardModifier::ShiftModifier)) return callEventAction( &EventActionInterface::multiSelectActionPress, x, y ); return false; } /* EventDispatcher::onPress */ bool EventDispatcher::onClick(int x, int y, Qt::KeyboardModifiers mod) { Q_UNUSED(x); Q_UNUSED(y); if (mod == Qt::NoModifier) { bool ret = callEventAction( &EventActionInterface::setCoordinateAction, x, y ); if (ret) { EventActionInterface * eaIf = getEventActions(); if (eaIf) eaIf->userActionFinished(); } return ret; } if (mod.testFlag( Qt::KeyboardModifier::ShiftModifier )) return callEventAction( &EventActionInterface::multiSelectActionRelease, x, y ); return false; } /* EventDispatcher::onClick */ bool EventDispatcher::onMenuPress(int x, int y, Qt::KeyboardModifiers mod) { Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(mod); return false; } /* EventDispatcher::onMenuPress */ bool EventDispatcher::onMenuClick(int x, int y, Qt::KeyboardModifiers mod) { Q_UNUSED(mod); return callEventAction( &EventActionInterface::contextMenuAction, x, y ); } /* EventDispatcher::onMenuClick */ bool EventDispatcher::onDoubleClick(int x, int y, Qt::KeyboardModifiers ) { callEventAction( &EventActionInterface::completeStateAction, x, y ); return true; } /* EventDispatcher::onDoubleClick */ bool EventDispatcher::onDoDelete() { if (_getEventsFrom != nullptr) { QPoint cursorPos = _getEventsFrom->mapFromGlobal( QCursor::pos() ); callEventAction( &EventActionInterface::selectAction, cursorPos.x(), cursorPos.y() ); bool ret = callEventAction( &EventActionInterface::deleteAction, cursorPos.x(), cursorPos.y() ); if (ret) { EventActionInterface * eaIf = getEventActions(); if (eaIf) eaIf->userActionFinished(); } return ret; } return false; } /* EventDispatcher::onDoDelete */ bool EventDispatcher::onDoUndo() { bool ret = callEventAction( &EventActionInterface::undoAction, 0, 0 ); if (ret) { EventActionInterface * eaIf = getEventActions(); if (eaIf) eaIf->userActionFinished(); } return ret; } /* EventDispatcher::onDoUndo */ bool EventDispatcher::onDoEscape() { EventActionInterface * eventActions = getEventActions(); KickTheBucket(); if (eventActions) eventActions->abortAction( this, 0, 0 ); return true; } /* EventDispatcher::onDoEscape */ bool EventDispatcher::onDoEnd() { EventActionInterface * eventActions = getEventActions(); KickTheBucket(); if (eventActions) eventActions->applyAndEndAction( this, 0, 0 ); return true; } /* EventDispatcher::onDoEnd */ } } /* namespace SituationMap::RB */