Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/Rubberbands/event_dispatcher.cpp
T
2026-08-13 18:33:10 +02:00

627 lines
20 KiB
C++
Executable File

/**
**
** @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 <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtWidgets/QGesture>
#include <QtWidgets/QWidget>
#include <QMetaMethod>
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<QGesture*> & 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<QTapGesture *>(gesture); typeName = QLatin1String("TapGesture"); break;
case Qt::TapAndHoldGesture : tapAndHoldGesture = static_cast<QTapAndHoldGesture*>(gesture); typeName = QLatin1String("TapAndHoldGesture"); break;
case Qt::PanGesture : panGesture = static_cast<QPanGesture *>(gesture); typeName = QLatin1String("PanGesture"); break;
case Qt::PinchGesture : pinchGesture = static_cast<QPinchGesture *>(gesture); typeName = QLatin1String("PinchGesture"); break;
case Qt::SwipeGesture : swipeGesture = static_cast<QSwipeGesture *>(gesture); typeName = QLatin1String("SwipeGesture"); break;
default:
{
if (gestureType == _applyGestureID)
{
applyGesture = static_cast<ApplyGesture*>(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<QMouseEvent*>(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<QTouchEvent*>(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<QMouseEvent*>(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<QMouseEvent*>(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<QTouchEvent*>(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<QMouseEvent*>(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<QTouchEvent*>(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<QKeyEvent*>(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<QWheelEvent*>(e);
if (wheelEvent->modifiers() & (Qt::KeyboardModifier::ShiftModifier | Qt::KeyboardModifier::ControlModifier))
{
handled = eventFilterWheel( wheelEvent );
}
} break;
case QEvent::Gesture:
{
handled = eventFilterGesture( static_cast<QGestureEvent*>(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 */