Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,23 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
SET(QT_MIN_VERSION 5.4.0)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
FILE ( GLOB sourceFiles *.h *.cpp )
|
||||
|
||||
FIND_PACKAGE(OpenGL)
|
||||
FIND_PACKAGE(Qt5 COMPONENTS Core Gui Location OpenGL Positioning Sensors Widgets REQUIRED)
|
||||
|
||||
INCLUDE_DIRECTORIES ( ${Qt5Widgets_INCLUDE_DIRS}, "C:/Program Files (x86)/ArcGIS SDKs/Qt10.2.6/sdk/windows/include" )
|
||||
|
||||
add_definitions(${Qt5Widgets_DEFINITIONS})
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
ADD_EXECUTABLE( EsriMapTouchTest WIN32 ${sourceFiles} )
|
||||
|
||||
TARGET_LINK_LIBRARIES( EsriMapTouchTest Qt5::Core Qt5::Gui Qt5::Location Qt5::OpenGL Qt5::Sensors Qt5::Widgets )
|
||||
TARGET_LINK_LIBRARIES( EsriMapTouchTest debug "C:/Program Files (x86)/ArcGIS SDKs/Qt10.2.6/sdk/windows/x86/lib/EsriRuntimeQtd.lib" )
|
||||
TARGET_LINK_LIBRARIES( EsriMapTouchTest optimized "C:/Program Files (x86)/ArcGIS SDKs/Qt10.2.6/sdk/windows/x86/lib/EsriRuntimeQt.lib" )
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Abstract Event Dispatcher for Qt5
|
||||
** $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 "abstract_event_dispatcher.h"
|
||||
#include "gestures.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <QtGui/QBitmap>
|
||||
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QWheelEvent>
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <QtCore/QDebug> // for debugging only
|
||||
|
||||
|
||||
namespace SituationMap { namespace RB
|
||||
{
|
||||
|
||||
|
||||
QGestureRecognizer * AbstractEventDispatcher::_applyGestureDetection = nullptr;
|
||||
unsigned int AbstractEventDispatcher::_applyGestureID = 0;
|
||||
|
||||
|
||||
AbstractEventDispatcher::AbstractEventDispatcher( QWidget * getEventsFrom )
|
||||
: QObject(getEventsFrom)
|
||||
, _getEventsFrom(getEventsFrom)
|
||||
, _cursorIsInWidget(false)
|
||||
, _ignoreMouseMoveTimestamp()
|
||||
, _synthesisTouchFromMouseEvents(false)
|
||||
, _deleteRequested(false)
|
||||
, _hasGrab(false)
|
||||
, _finishFlag(false)
|
||||
, _activeEvent(false)
|
||||
, _dispatcherCursor()
|
||||
, _whatsThisBackup()
|
||||
, _eventActions(nullptr)
|
||||
{
|
||||
initDispatcher();
|
||||
} /* AbstractEventDispatcher::AbstractEventDispatcher */
|
||||
|
||||
|
||||
AbstractEventDispatcher::AbstractEventDispatcher( QWidget * getEventsFrom, EventActionInterface * eventActions )
|
||||
: QObject(getEventsFrom)
|
||||
, _getEventsFrom(getEventsFrom)
|
||||
, _cursorIsInWidget(false)
|
||||
, _ignoreMouseMoveTimestamp()
|
||||
, _synthesisTouchFromMouseEvents(false)
|
||||
, _deleteRequested(false)
|
||||
, _hasGrab(false)
|
||||
, _finishFlag(false)
|
||||
, _activeEvent(false)
|
||||
, _dispatcherCursor()
|
||||
, _whatsThisBackup()
|
||||
, _eventActions(eventActions)
|
||||
|
||||
{
|
||||
initDispatcher();
|
||||
} /* AbstractEventDispatcher::AbstractEventDispatcher */
|
||||
|
||||
|
||||
void AbstractEventDispatcher::initDispatcher()
|
||||
{
|
||||
_restoreCursor = true;
|
||||
|
||||
/* The methode QWidget::ownCursor doesn't exist any more.
|
||||
* Try to find out if the inherited from parent
|
||||
*/
|
||||
|
||||
// _restoreCursor = getEventsFrom->ownCursor();
|
||||
|
||||
if (_restoreCursor)
|
||||
{
|
||||
_cursorToRestore = getCursorFromWidget();
|
||||
}
|
||||
_restoreMouseTracking = _getEventsFrom->hasMouseTracking();
|
||||
|
||||
// just a test exe, but remove process Events
|
||||
// QCoreApplication::process Events ( ); /// removePostedEvents( _getEventsFrom );
|
||||
|
||||
_getEventsFrom->setMouseTracking(true);
|
||||
_getEventsFrom->raise();
|
||||
_getEventsFrom->installEventFilter(this);
|
||||
|
||||
_synthesisTouchFromMouseEvents = QCoreApplication::testAttribute( Qt::AA_SynthesizeTouchForUnhandledMouseEvents );
|
||||
QCoreApplication::setAttribute( Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false );
|
||||
QCoreApplication::setAttribute( Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true );
|
||||
#ifdef NEVER
|
||||
static const Qt::GestureType gestures[] = { Qt::GestureType::TapGesture
|
||||
, Qt::GestureType::TapAndHoldGesture
|
||||
, Qt::GestureType::PanGesture
|
||||
, Qt::GestureType::PinchGesture
|
||||
, Qt::GestureType::SwipeGesture };
|
||||
|
||||
for (auto gestureType : gestures) _getEventsFrom->grabGesture(gestureType);
|
||||
|
||||
if (_applyGestureDetection == nullptr)
|
||||
{
|
||||
_applyGestureDetection = new ApplyGestureRecognizer();
|
||||
_applyGestureID = QGestureRecognizer::registerRecognizer( _applyGestureDetection );
|
||||
}
|
||||
|
||||
_getEventsFrom->grabGesture( (Qt::GestureType)_applyGestureID );
|
||||
_getEventsFrom->setAttribute( Qt::WA_AcceptTouchEvents, true );
|
||||
#endif
|
||||
} /* AbstractEventDispatcher::initDispatcher */
|
||||
|
||||
|
||||
AbstractEventDispatcher::~AbstractEventDispatcher()
|
||||
{
|
||||
|
||||
_finishFlag = true;
|
||||
|
||||
if (_getEventsFrom)
|
||||
{
|
||||
_getEventsFrom->removeEventFilter(this);
|
||||
_getEventsFrom->setMouseTracking( _restoreMouseTracking );
|
||||
|
||||
ungrab();
|
||||
|
||||
if (!_whatsThisBackup.isNull())
|
||||
{
|
||||
_getEventsFrom->setWhatsThis(_whatsThisBackup);
|
||||
}
|
||||
}
|
||||
QCoreApplication::setAttribute( Qt::AA_SynthesizeTouchForUnhandledMouseEvents, _synthesisTouchFromMouseEvents );
|
||||
|
||||
} /* AbstractEventDispatcher::~AbstractEventDispatcher */
|
||||
|
||||
|
||||
void AbstractEventDispatcher::onDo_delete()
|
||||
{
|
||||
if (_deleteRequested) return;
|
||||
_deleteRequested = true;
|
||||
QObject::deleteLater();
|
||||
} /* AbstractEventDispatcher::onDo_delete */
|
||||
|
||||
|
||||
void AbstractEventDispatcher::KickTheBucket()
|
||||
{
|
||||
if (_getEventsFrom == nullptr) return;
|
||||
|
||||
_finishFlag = true;
|
||||
|
||||
unlinkEventDispatcher();
|
||||
|
||||
_getEventsFrom->removeEventFilter(this);
|
||||
_getEventsFrom->setMouseTracking( _restoreMouseTracking );
|
||||
|
||||
ungrab();
|
||||
|
||||
if (!_whatsThisBackup.isNull())
|
||||
{
|
||||
_getEventsFrom->setWhatsThis(_whatsThisBackup);
|
||||
}
|
||||
|
||||
_getEventsFrom = nullptr;
|
||||
|
||||
emit signalKickTheBucket();
|
||||
|
||||
QCoreApplication::flush();
|
||||
// just a test exe, but remove process Events
|
||||
// QCoreApplication::process Events(); // dispatch window system events
|
||||
|
||||
onDo_delete();
|
||||
|
||||
} /* AbstractEventDispatcher::KickTheBucket */
|
||||
|
||||
|
||||
void AbstractEventDispatcher::onDo_kickTheBucket() { KickTheBucket(); }
|
||||
|
||||
|
||||
void AbstractEventDispatcher::setWhatsThis(const QString & whatsThis)
|
||||
{
|
||||
if (_whatsThisBackup.isNull())
|
||||
{
|
||||
_whatsThisBackup = _getEventsFrom->whatsThis();
|
||||
}
|
||||
_getEventsFrom->setWhatsThis(whatsThis);
|
||||
} /* AbstractEventDispatcher::setWhatsThis */
|
||||
|
||||
|
||||
|
||||
void AbstractEventDispatcher::grab()
|
||||
{
|
||||
if (_hasGrab) return;
|
||||
_hasGrab = true;
|
||||
|
||||
setCursorToWidget( _dispatcherCursor );
|
||||
_getEventsFrom -> setFocus();
|
||||
} /* AbstractEventDispatcher::Grab */
|
||||
|
||||
|
||||
void AbstractEventDispatcher::ungrab()
|
||||
{
|
||||
if (!_hasGrab) return;
|
||||
|
||||
_hasGrab = false;
|
||||
if (_restoreCursor)
|
||||
{
|
||||
setCursorToWidget( _cursorToRestore );
|
||||
}
|
||||
// else _getEventsFrom -> unsetCursor();
|
||||
|
||||
_getEventsFrom -> clearFocus();
|
||||
|
||||
} /* AbstractEventDispatcher::Ungrab */
|
||||
|
||||
|
||||
bool AbstractEventDispatcher::eventFilter( QObject * widget, QEvent * e )
|
||||
{
|
||||
if (widget != ((QObject*)_getEventsFrom)) return false;
|
||||
|
||||
|
||||
return false;
|
||||
} /* AbstractEventDispatcher::eventFilter */
|
||||
|
||||
|
||||
void AbstractEventDispatcher::setCursorToWidget( const QCursor & cursor )
|
||||
{
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* The cursor handling of QGraphicView are not free of bugs. If it tries to restore the default cursor after setting a special cursor for one item
|
||||
* it can happend that the restored cursor is not the last cursor that was set with setCursor function because the internal stored restore cursor is
|
||||
* not updated with setCursor function. As work around a mouse move event is send to the widget to reset cursor handling.
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
const QPoint & currentCursorPosition = _getEventsFrom->mapFromGlobal( QCursor::pos() );
|
||||
|
||||
#ifdef ShowBug
|
||||
QMouseEvent && mouseEvent = QMouseEvent( QEvent::Type::MouseMove, QPointF(-1,-1), Qt::MouseButton::NoButton, Qt::MouseButtons(), Qt::KeyboardModifier::NoModifier );
|
||||
|
||||
_ignoreMouseMoveTimestamp = mouseEvent.timestamp();
|
||||
|
||||
QCoreApplication::sendEvent(_getEventsFrom, &mouseEvent );
|
||||
QCoreApplication::process Events();
|
||||
|
||||
_getEventsFrom -> setCursor( cursor );
|
||||
|
||||
if (_cursorIsInWidget)
|
||||
{
|
||||
mouseEvent = QMouseEvent( QEvent::Type::MouseMove, currentCursorPosition, Qt::MouseButton::NoButton, Qt::MouseButtons(), Qt::KeyboardModifier::NoModifier );
|
||||
QCoreApplication::sendEvent(_getEventsFrom, &mouseEvent );
|
||||
}
|
||||
QCoreApplication::process Events();
|
||||
_getEventsFrom -> update();
|
||||
#else
|
||||
_getEventsFrom -> setCursor( cursor );
|
||||
#endif
|
||||
} /* AbstractEventDispatcher::setCursorToWidget */
|
||||
|
||||
|
||||
QCursor AbstractEventDispatcher::getCursorFromWidget()
|
||||
{
|
||||
const QPoint & currentCursorPosition = _getEventsFrom->mapFromGlobal( QCursor::pos() );
|
||||
|
||||
#ifdef ShowBug
|
||||
QMouseEvent && mouseEvent = QMouseEvent( QEvent::Type::MouseMove, QPointF(-1,-1), Qt::MouseButton::NoButton, Qt::MouseButtons(), Qt::KeyboardModifier::NoModifier );
|
||||
|
||||
_ignoreMouseMoveTimestamp = mouseEvent.timestamp();
|
||||
|
||||
QCoreApplication::sendEvent(_getEventsFrom, &mouseEvent );
|
||||
QCoreApplication::process Events();
|
||||
|
||||
const QCursor & currentCursor = _getEventsFrom->cursor();
|
||||
|
||||
if (_cursorIsInWidget)
|
||||
{
|
||||
mouseEvent = QMouseEvent( QEvent::Type::MouseMove, currentCursorPosition, Qt::MouseButton::NoButton, Qt::MouseButtons(), Qt::KeyboardModifier::NoModifier );
|
||||
QCoreApplication::sendEvent(_getEventsFrom, &mouseEvent );
|
||||
}
|
||||
QCoreApplication::process Events();
|
||||
_getEventsFrom -> update();
|
||||
#else
|
||||
const QCursor & currentCursor = _getEventsFrom->cursor();
|
||||
#endif
|
||||
return currentCursor;
|
||||
} /* AbstractEventDispatcher::getCursorFromWidget */
|
||||
|
||||
|
||||
} } /* namespace SituationMap::RB */
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Abstract Event Dispatcher for Qt5
|
||||
** $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
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QEvent>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QTime>
|
||||
|
||||
#include <QtGui/QCursor>
|
||||
|
||||
|
||||
class QWidget;
|
||||
class QWheelEvent;
|
||||
class QGestureRecognizer;
|
||||
|
||||
|
||||
namespace SituationMap { namespace RB
|
||||
{
|
||||
|
||||
/**
|
||||
@class AbstractEventDispatcher abstract_event_dispatcher.h
|
||||
@brief Base class of Qt event filter implementations to handle user interactions of map window
|
||||
|
||||
An EventDispatcher installs an event filter on a QWidget to receive all events that are send to
|
||||
the widget. Depending on the type of event and the state of the event dispatcher the event will
|
||||
be processed by the dispatcher and stopped or forwarded to the QWidget. In case of processing
|
||||
the event methodes of the EventActionInterface are called to controll a rubberband.
|
||||
|
||||
@see EventDelegater, EventDispatcher, EventMouseNavigator
|
||||
*/
|
||||
class AbstractEventDispatcher : public QObject
|
||||
{
|
||||
friend class EventDelegater;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@brief Logical interface between EventDispatcher and Rubberband
|
||||
Defines interface functions the EventDispatcher will call to control a rubberband. The rubberband class
|
||||
is derived from EventActionInterface and overrides the interface functions to implement them. The mapping
|
||||
user interaction to interface action is defined the derived classes of AbstractEventDispatcher.
|
||||
*/
|
||||
class EventActionInterface
|
||||
{
|
||||
public:
|
||||
|
||||
EventActionInterface() = default;
|
||||
virtual ~EventActionInterface() = default;
|
||||
|
||||
virtual void unlinkEventDispatcher( AbstractEventDispatcher * causer ) = 0;
|
||||
|
||||
virtual bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool multiSelectAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool setCoordinateAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool moveAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool movePickedAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual void resetAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool contextMenuAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool completeStateAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool deleteAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool undoAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool applyAndEndAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
virtual bool abortAction ( AbstractEventDispatcher * causer, int x, int y ) = 0;
|
||||
|
||||
}; /* EventActionInterface */
|
||||
|
||||
/**
|
||||
@name Construction & Destruction
|
||||
@{
|
||||
*/
|
||||
AbstractEventDispatcher( QWidget * getEventsFrom );
|
||||
AbstractEventDispatcher( QWidget * getEventsFrom, EventActionInterface* );
|
||||
|
||||
virtual ~AbstractEventDispatcher();
|
||||
|
||||
AbstractEventDispatcher(const AbstractEventDispatcher &) = delete;
|
||||
AbstractEventDispatcher & operator = (const AbstractEventDispatcher &) = delete;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
Conceal deleteLater slot. Use onDo_delete() instead to avoid "QCoreApplication::postEvent: Unexpected null receiver" warning.
|
||||
*/
|
||||
void deleteLater() = delete;
|
||||
|
||||
|
||||
inline void setEventActions(EventActionInterface * eventActions) { _eventActions = eventActions; }
|
||||
|
||||
inline bool hasGrab() const { return _hasGrab; }
|
||||
|
||||
inline void setCursor(const QCursor & cursor) { _dispatcherCursor = cursor; }
|
||||
|
||||
void setWhatsThis(const QString & whatsThis);
|
||||
|
||||
virtual void grab();
|
||||
virtual void ungrab();
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@brief Slot calling internal \c KickTheBucket methode
|
||||
|
||||
Calls internal methode \c KickTheBucket. Be careful using this function. Should only be used
|
||||
from implementations of \c EventActionInterface methodes or \c EventDelegater class.
|
||||
*/
|
||||
void onDo_kickTheBucket();
|
||||
|
||||
/**
|
||||
@brief Slot calling \c deleteLater function of QObject
|
||||
|
||||
Never use \c delete directly for EventDispatcher class. Instead of use \c onDo_delete() function.
|
||||
*/
|
||||
void onDo_delete();
|
||||
|
||||
protected:
|
||||
|
||||
QWidget * _getEventsFrom;
|
||||
bool _cursorIsInWidget;
|
||||
|
||||
inline bool hasFinished() { return _finishFlag; }
|
||||
inline bool hasActiveEvent() { return _activeEvent; }
|
||||
|
||||
inline void setActiveEvent(bool val) { _activeEvent = val; }
|
||||
|
||||
/**
|
||||
@brief Destroying EventDispatcher as result of an incoming event.
|
||||
|
||||
As result of an incomming event (e.g. Keypress ESC) the EventDispatcher will stop, emiting signal \c signalKickTheBucket()
|
||||
and calls methode \c EventActionInterface::unlinkEventDispatcher() before setup \c deleteLater() call to destroy it self.
|
||||
*/
|
||||
virtual void KickTheBucket();
|
||||
|
||||
|
||||
inline void unlinkEventDispatcher()
|
||||
{
|
||||
if (_eventActions)
|
||||
{
|
||||
_eventActions -> unlinkEventDispatcher( this );
|
||||
_eventActions = nullptr;
|
||||
}
|
||||
} /* unlinkEventDispatcher */
|
||||
|
||||
|
||||
inline bool callEventAction( bool( EventActionInterface::*actionMethodePtr)( AbstractEventDispatcher*,int,int), int x, int y )
|
||||
{
|
||||
if (_eventActions == nullptr) return false;
|
||||
return (_eventActions->*actionMethodePtr)( this, x, y );
|
||||
} /* callEventAction */
|
||||
|
||||
|
||||
/**
|
||||
Event filter function to override to implement event handling. To workaround a cursor handling bug in QGraphicsView it is
|
||||
necessary to call the eventFilter function of this base class, which will monitor enter and leave events.
|
||||
*/
|
||||
virtual bool eventFilter( QObject * widget, QEvent * e );
|
||||
|
||||
inline EventActionInterface * getEventActions() const { return _eventActions; }
|
||||
|
||||
void setCursorToWidget( const QCursor & cursor );
|
||||
QCursor getCursorFromWidget();
|
||||
|
||||
ulong _ignoreMouseMoveTimestamp;
|
||||
|
||||
bool _synthesisTouchFromMouseEvents;
|
||||
|
||||
static unsigned int _applyGestureID;
|
||||
|
||||
private:
|
||||
|
||||
void initDispatcher();
|
||||
|
||||
bool _deleteRequested;
|
||||
|
||||
bool _hasGrab;
|
||||
bool _finishFlag;
|
||||
|
||||
bool _restoreCursor;
|
||||
bool _restoreMouseTracking;
|
||||
QCursor _cursorToRestore;
|
||||
|
||||
bool _activeEvent;
|
||||
|
||||
QCursor _dispatcherCursor;
|
||||
QString _whatsThisBackup;
|
||||
|
||||
EventActionInterface * _eventActions;
|
||||
|
||||
|
||||
|
||||
static QGestureRecognizer * _applyGestureDetection;
|
||||
|
||||
signals:
|
||||
|
||||
void signalKickTheBucket();
|
||||
|
||||
}; /* EventDispatcher */
|
||||
|
||||
} } /* namespace SituationMap::RB */
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Event Dispatcher for Qt5 to delegate mouse and keyboard event to another event dispatcher
|
||||
** $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 .........:
|
||||
**
|
||||
** 15.04.2015, JT : First edition
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "event_mouse_navigator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QWheelEvent>
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QGesture>
|
||||
#include <QtWidgets/QGraphicsSceneMouseEvent>
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include <QtCore/QDebug> // for debugging only
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <Map.h>
|
||||
#include <Layer.h>
|
||||
#include <FeatureLayer.h>
|
||||
#include <GraphicsLayer.h>
|
||||
#include <MessageGroupLayer.h>
|
||||
#include <Graphic.h>
|
||||
|
||||
|
||||
namespace SituationMap { namespace RB
|
||||
{
|
||||
|
||||
int EventMouseNavigator::_pickTolerance = 20;
|
||||
|
||||
EventMouseNavigator::EventMouseNavigator(QWidget * getEventsFrom, EsriRuntimeQt::Map * esriMap )
|
||||
: AbstractEventDispatcher(getEventsFrom)
|
||||
, _esriMap(esriMap)
|
||||
, _selectionMode()
|
||||
, _selectedIdList()
|
||||
, _idConnectionCount(0)
|
||||
, _mousePanningActive(false)
|
||||
{
|
||||
} /* EventMouseNavigator::EventMouseNavigator */
|
||||
|
||||
|
||||
bool EventMouseNavigator::eventFilter(QObject * watched, QEvent * 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::MouseButtonPress :
|
||||
{
|
||||
debugString = QLatin1String("mouse button press event");
|
||||
|
||||
QMouseEvent * mouseEvent = static_cast<QMouseEvent*>(e);
|
||||
|
||||
_mousePanningActive = false;
|
||||
|
||||
_mouseMoveRefPos = mouseEvent->pos();
|
||||
_restoreMouseCursor = getCursorFromWidget();
|
||||
|
||||
if (Qt::LeftButton == mouseEvent->button())
|
||||
{
|
||||
handled = false;
|
||||
|
||||
if (mouseEvent->modifiers() == Qt::KeyboardModifier::ControlModifier)
|
||||
{
|
||||
_selectionMode = SelectionMode::MultiSelection;
|
||||
setCursorToWidget( QCursor(Qt::CursorShape::PointingHandCursor) );
|
||||
}
|
||||
else if (mouseEvent->modifiers().testFlag( Qt::KeyboardModifier::ShiftModifier ))
|
||||
{
|
||||
_selectionMode = SelectionMode::FrameSelection;
|
||||
if (mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
|
||||
{
|
||||
_selectionMode &= SelectionMode::MultiSelection;
|
||||
}
|
||||
else
|
||||
{
|
||||
_selectionMode &= SelectionMode::SingleSelection;
|
||||
}
|
||||
setCursorToWidget( QCursor(Qt::CursorShape::SizeAllCursor) );
|
||||
}
|
||||
else
|
||||
{
|
||||
setCursorToWidget( QCursor(Qt::CursorShape::ArrowCursor) );
|
||||
_selectionMode = SelectionMode::SingleSelection;
|
||||
}
|
||||
}
|
||||
|
||||
if (Qt::MidButton == mouseEvent->button())
|
||||
{
|
||||
handled = (Qt::MidButton == mouseEvent->button());
|
||||
|
||||
_mousePanningActive = true;
|
||||
setCursorToWidget( QCursor(Qt::CursorShape::ClosedHandCursor) );
|
||||
}
|
||||
} break;
|
||||
|
||||
case QEvent::MouseButtonRelease :
|
||||
{
|
||||
debugString = QLatin1String("mouse button release event");
|
||||
|
||||
QMouseEvent * mouseEvent = static_cast<QMouseEvent*>(e);
|
||||
|
||||
if (Qt::LeftButton == mouseEvent->button())
|
||||
{
|
||||
handled = false;
|
||||
|
||||
if (!_mousePanningActive)
|
||||
{
|
||||
setCursorToWidget( _restoreMouseCursor );
|
||||
|
||||
selectionRequested( mouseEvent->pos() );
|
||||
|
||||
_selectionMode = SelectionMode::NoSelection;
|
||||
// do not handled = true; because some buttons in GraphicsView needs to get the event later.
|
||||
}
|
||||
}
|
||||
|
||||
if (Qt::RightButton == mouseEvent->button())
|
||||
{
|
||||
handled = true;
|
||||
pickRequested( mouseEvent->pos() );
|
||||
}
|
||||
|
||||
if ((_mousePanningActive) || (Qt::MidButton == mouseEvent->button()))
|
||||
{
|
||||
handled = (Qt::MidButton == mouseEvent->button());
|
||||
setCursorToWidget( _restoreMouseCursor );
|
||||
}
|
||||
|
||||
_mousePanningActive = false;
|
||||
} break;
|
||||
|
||||
case QEvent::MouseMove :
|
||||
{
|
||||
debugString = QLatin1String("mouse button move event");
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
|
||||
|
||||
if (mouseEvent->timestamp() != _ignoreMouseMoveTimestamp)
|
||||
{
|
||||
if (isSignalConnected(QMetaMethod::fromSignal(&EventMouseNavigator::mouseMovedEvent)))
|
||||
{
|
||||
mouseMovedEvent( mouseEvent->pos().x(), mouseEvent->pos().y() );
|
||||
}
|
||||
|
||||
if ((!_mousePanningActive) && mouseEvent->buttons().testFlag(Qt::LeftButton))
|
||||
{
|
||||
QPoint deltaMove = mouseEvent->pos()-_mouseMoveRefPos;
|
||||
if (deltaMove.manhattanLength() > 3)
|
||||
{
|
||||
_mousePanningActive = true;
|
||||
setCursorToWidget( QCursor(Qt::CursorShape::ClosedHandCursor) );
|
||||
}
|
||||
}
|
||||
|
||||
if ((_mousePanningActive) || mouseEvent->buttons().testFlag(Qt::MidButton))
|
||||
{
|
||||
handled = true;
|
||||
EsriRuntimeQt::AnimationMode mode = _esriMap->animationMode();
|
||||
|
||||
QPoint deltaMove = mouseEvent->pos()-_mouseMoveRefPos;
|
||||
QPoint winCenter = QPoint( _getEventsFrom->width() / 2, _getEventsFrom->height() / 2 );
|
||||
QPoint newCenter = winCenter-deltaMove;
|
||||
|
||||
const EsriRuntimeQt::Point & mapCenter = _esriMap->toMapPoint(newCenter.x(), newCenter.y());
|
||||
|
||||
_esriMap -> setAnimationMode( EsriRuntimeQt::AnimationMode::NoAnimation );
|
||||
_esriMap -> panTo( mapCenter );
|
||||
_esriMap -> setAnimationMode(mode);
|
||||
|
||||
_getEventsFrom -> update();
|
||||
|
||||
_mouseMoveRefPos = mouseEvent->pos();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case QEvent::Wheel :
|
||||
{
|
||||
debugString = QLatin1String("mouse wheel event");
|
||||
// QWheelEvent * wheelEvent = static_cast<QWheelEvent*>(e);
|
||||
// handled = true;
|
||||
handled = false;
|
||||
} break;
|
||||
|
||||
case QEvent::Gesture:
|
||||
{
|
||||
QGestureEvent * gestureEvent = static_cast<QGestureEvent*>(e);
|
||||
|
||||
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;
|
||||
QString typeName;
|
||||
QString stateName;
|
||||
|
||||
switch (gestureType)
|
||||
{
|
||||
case Qt::TapGesture : tapGesture = (QTapGesture *)gesture; typeName = QLatin1String("TapGesture"); break;
|
||||
case Qt::TapAndHoldGesture : tapAndHoldGesture = (QTapAndHoldGesture*)gesture; typeName = QLatin1String("TapAndHoldGesture"); break;
|
||||
case Qt::PanGesture : panGesture = (QPanGesture *)gesture; typeName = QLatin1String("PanGesture"); break;
|
||||
case Qt::PinchGesture : pinchGesture = (QPinchGesture *)gesture; typeName = QLatin1String("PinchGesture"); break;
|
||||
case Qt::SwipeGesture : swipeGesture = (QSwipeGesture *)gesture; typeName = QLatin1String("SwipeGesture"); break;
|
||||
|
||||
default: 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;
|
||||
}
|
||||
|
||||
// tapGesture = nullptr;
|
||||
panGesture = nullptr;
|
||||
|
||||
if (panGesture)
|
||||
{
|
||||
EsriRuntimeQt::AnimationMode mode = _esriMap->animationMode();
|
||||
|
||||
QPointF deltaMove = panGesture->delta();
|
||||
QPoint winCenter = QPoint( _getEventsFrom->width() / 2, _getEventsFrom->height() / 2 );
|
||||
QPoint newCenter = winCenter-QPoint((int)deltaMove.x(),(int)deltaMove.y());
|
||||
|
||||
const EsriRuntimeQt::Point & mapCenter = _esriMap->toMapPoint(newCenter.x(), newCenter.y());
|
||||
|
||||
_esriMap -> setAnimationMode( EsriRuntimeQt::AnimationMode::NoAnimation );
|
||||
_esriMap -> panTo( mapCenter );
|
||||
_esriMap -> setAnimationMode(mode);
|
||||
|
||||
_getEventsFrom -> update();
|
||||
|
||||
if (gestureState == Qt::GestureStarted) gestureEvent -> setAccepted(panGesture, true);
|
||||
|
||||
}
|
||||
|
||||
if (pinchGesture)
|
||||
{
|
||||
EsriRuntimeQt::AnimationMode mode = _esriMap->animationMode();
|
||||
QPinchGesture::ChangeFlags changeFlags = pinchGesture->changeFlags();
|
||||
|
||||
_esriMap -> setAnimationMode( EsriRuntimeQt::AnimationMode::NoAnimation );
|
||||
|
||||
if (changeFlags & QPinchGesture::RotationAngleChanged)
|
||||
{
|
||||
qreal deltaPhi = pinchGesture->rotationAngle() - pinchGesture->lastRotationAngle();
|
||||
_esriMap -> setRotation( _esriMap->rotation()-deltaPhi );
|
||||
}
|
||||
if (changeFlags & QPinchGesture::ScaleFactorChanged) _esriMap -> zoom( 1.0/pinchGesture->scaleFactor() );
|
||||
|
||||
_esriMap -> setAnimationMode(mode);
|
||||
|
||||
_getEventsFrom -> update();
|
||||
|
||||
if (gestureState == Qt::GestureStarted) gestureEvent -> setAccepted(pinchGesture, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
|
||||
} /* switch */
|
||||
|
||||
if (!hasFinished()) setActiveEvent( false );
|
||||
|
||||
if (handled) e->accept();
|
||||
|
||||
if (handled) return true;
|
||||
}
|
||||
return AbstractEventDispatcher::eventFilter(watched,e);
|
||||
|
||||
} /* EventMouseNavigator::eventFilter */
|
||||
|
||||
|
||||
void EventMouseNavigator::selectionRequested( const QPoint & pos )
|
||||
{
|
||||
const bool appendSelection = _selectionMode.testFlag( SelectionMode::MultiSelection );
|
||||
|
||||
if (isSignalConnected( QMetaMethod::fromSignal(&EventMouseNavigator::selectionRequest) ))
|
||||
{
|
||||
// do the work only in case of slot connections are installed
|
||||
|
||||
if (0 != _idConnectionCount)
|
||||
{
|
||||
qWarning() << LOGFUNCTION << " graphic layer id list request is still pending!";
|
||||
return;
|
||||
}
|
||||
|
||||
pickObjects( pos, _selectedIdList, appendSelection, &EventMouseNavigator::selectionRequest );
|
||||
|
||||
}
|
||||
} /* EventMouseNavigator::selectionRequested */
|
||||
|
||||
|
||||
void EventMouseNavigator::pickRequested( const QPoint & pos )
|
||||
{
|
||||
if (isSignalConnected( QMetaMethod::fromSignal(&EventMouseNavigator::contextMenuRequest) ))
|
||||
{
|
||||
// do the work only in case of slot connections are installed
|
||||
|
||||
if (0 != _idConnectionCount)
|
||||
{
|
||||
qWarning() << LOGFUNCTION << " graphic layer id list request is still pending!";
|
||||
return;
|
||||
}
|
||||
|
||||
pickObjects( pos, _selectedIdList, false, &EventMouseNavigator::contextMenuRequest );
|
||||
|
||||
}
|
||||
} /* EventMouseNavigator::pickRequested */
|
||||
|
||||
|
||||
void EventMouseNavigator::pickObjects( const QPoint & pos
|
||||
, QList<uint> & pickIdList
|
||||
, bool append
|
||||
, void (EventMouseNavigator::*pickSignal)(const QList< uint>&,QPoint) )
|
||||
{
|
||||
#ifdef NEVER
|
||||
if (!append) _selectedIdList.clear();
|
||||
|
||||
QList<EsriRuntimeQt::Layer*> layerList = _esriMap->layers();
|
||||
QList<EsriRuntimeQt::Layer*> selectLayerList;
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~ first look for all layers in map ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
for (auto layer : layerList)
|
||||
{
|
||||
EsriRuntimeQt::MessageGroupLayer* msgGrpLayer = qobject_cast<EsriRuntimeQt::MessageGroupLayer*>(layer);
|
||||
if (msgGrpLayer)
|
||||
{
|
||||
selectLayerList.append( msgGrpLayer->getLayers() );
|
||||
}
|
||||
else selectLayerList.append(layer);
|
||||
}
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~ loop over all layers in layer list ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
for (auto layer : selectLayerList)
|
||||
{
|
||||
EsriRuntimeQt::FeatureLayer* featureLayer = qobject_cast<EsriRuntimeQt::FeatureLayer*>(layer);
|
||||
if (featureLayer)
|
||||
{
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~ get selected features by direct function call ~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
QList<qint64> fidList = featureLayer -> featureIds( pos.x(), pos.y(), _pickTolerance );
|
||||
featureLayer->selectFeatures( fidList, append );
|
||||
|
||||
EsriRuntimeQt::FeatureTable* featureTable = featureLayer->featureTable();
|
||||
|
||||
for (auto featureId : fidList)
|
||||
{
|
||||
if (featureTable)
|
||||
{
|
||||
EsriRuntimeQt::Feature* feature = featureTable->feature( featureId );
|
||||
if (feature)
|
||||
{
|
||||
bool ok;
|
||||
SituationMap::UniqueMapId id;
|
||||
|
||||
id = feature->property( SituationMap::UniqueMapIdProperty ).toUInt( &ok );
|
||||
if (ok)
|
||||
{
|
||||
if (!pickIdList.contains(id))
|
||||
{
|
||||
pickIdList += id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // for
|
||||
} // if (featureLayer)
|
||||
|
||||
EsriRuntimeQt::GraphicsLayer * graphicsLayer = qobject_cast<EsriRuntimeQt::GraphicsLayer*>(layer);
|
||||
if (graphicsLayer)
|
||||
{
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* In case of message symbols, in a graphic layer a slot method has to be used to get
|
||||
* the ids of selected symbols. The slot installed (connected) each time
|
||||
* EventMouseNavigator::selectionRequested() has been called and will be disconnect itself at
|
||||
* beginning of slot function. Because the slot methode will be called later, we have to store
|
||||
* some information like the _selectedIdList as member variable.
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* connect here, because the layer in MessageGroupLayer can change:
|
||||
* do not use QMetaObject:.Connection directly because disconnect will fail.
|
||||
* See also http://stackoverflow.com/questions/13847507/qt5-new-signal-to-lambda-connections-memory-leak
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
_idConnectionCount++;
|
||||
|
||||
auto conn = std::make_shared<QMetaObject::Connection>();
|
||||
*conn = connect( graphicsLayer, &EsriRuntimeQt::GraphicsLayer::graphicIdsComplete,
|
||||
this , [conn,pos,&pickIdList,graphicsLayer,pickSignal,this]( const QList<qint64>& gIdList )
|
||||
{
|
||||
disconnect( *conn );
|
||||
for (auto gId : gIdList)
|
||||
{
|
||||
QString objectName(QLatin1String(" - no graphic - "));
|
||||
|
||||
EsriRuntimeQt::Graphic * graphic = graphicsLayer->graphic(gId);
|
||||
if (graphic)
|
||||
objectName = graphic->objectName();
|
||||
|
||||
qDebug() << LOGFUNCTION
|
||||
<< " gId=" << gId
|
||||
<< " name= " << objectName;
|
||||
|
||||
if (graphic)
|
||||
{
|
||||
bool ok;
|
||||
SituationMap::UniqueMapId id;
|
||||
|
||||
id = graphic->property( SituationMap::UniqueMapIdProperty ).toUInt( &ok );
|
||||
if (ok)
|
||||
{
|
||||
if (!pickIdList.contains(id))
|
||||
{
|
||||
pickIdList += id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Just emit selectionRequest only once
|
||||
if (_idConnectionCount <= 1)
|
||||
{
|
||||
(this->*pickSignal)( pickIdList, pos );
|
||||
_idConnectionCount = 0;
|
||||
}
|
||||
else _idConnectionCount--;
|
||||
|
||||
} ); // end of lambda methode
|
||||
|
||||
graphicsLayer->graphicIds( pos.x(), pos.y(), _pickTolerance, 100 );
|
||||
|
||||
}
|
||||
} // for layer
|
||||
if (_idConnectionCount == 0)
|
||||
{
|
||||
(this->*pickSignal)( pickIdList, pos );
|
||||
}
|
||||
#endif
|
||||
} // EventMouseNavigator::pickObjects
|
||||
|
||||
|
||||
} } /* namespace SituationMap::RB */
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Event Dispatcher for Qt5 to handle mouse events navigate on map
|
||||
** $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 .........:
|
||||
**
|
||||
** 24.04.2015, JT : first edition
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QList>
|
||||
|
||||
#include "abstract_event_dispatcher.h"
|
||||
|
||||
|
||||
namespace EsriRuntimeQt
|
||||
{
|
||||
class Map;
|
||||
|
||||
} /* namespace EsriRuntimeQt */
|
||||
|
||||
|
||||
namespace SituationMap { namespace RB
|
||||
{
|
||||
|
||||
/**
|
||||
@class EventMouseNavigator event_mouse_navigator.h
|
||||
@brief Event filter that handles mouse events for general map operation like selecting object, zooming and paning the map window
|
||||
|
||||
Implements class \c AbstractEventDispatcher to manage event handling for general map operation like selecting object, zooming and
|
||||
panning the map window. Monitoring the mouse position can be realized by connecting the \c mouseMovedEvent signal. If the user has
|
||||
clicked to map objects the signal \c selectionRequest is emitted.
|
||||
|
||||
Following events are handled:
|
||||
|
||||
| Input-Event | Interface Function | Description |
|
||||
| :--------------------------------------------- | : ----------------- | : --------------------------------------------------------------------------- |
|
||||
| Mouse move without any modifier | | Move Cursor. |
|
||||
| Mouse move with pressed left button | | Panning of map if more then 3 pixels moved. |
|
||||
| Mouse move with pressed middle button | | Panning of map. |
|
||||
| Mouse wheel | | Redirect to \c Esri map for zooming. |
|
||||
| Left mouse button release | | Emits signal \c selectionRequest with list of map objects at cursor position. |
|
||||
|
||||
@see AbstractEventDispatcher, EventDelegater, EventDispatcher
|
||||
*/
|
||||
|
||||
class EventMouseNavigator : public AbstractEventDispatcher
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@name Construction & Destruction
|
||||
@{
|
||||
*/
|
||||
EventMouseNavigator(const EventMouseNavigator &) = delete;
|
||||
EventMouseNavigator & operator = (const EventMouseNavigator &) = delete;
|
||||
|
||||
EventMouseNavigator( QWidget * getEventsFrom, EsriRuntimeQt::Map * esriMap );
|
||||
|
||||
virtual ~EventMouseNavigator() {}
|
||||
/** @} */
|
||||
|
||||
inline static void setPickTolerance( int value = 20 ) { _pickTolerance = value; }
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
Will be emitted if the user clicks to map objects with the left mouse button.
|
||||
*/
|
||||
void selectionRequest( const QList< uint > & idList, QPoint viewPortPos );
|
||||
|
||||
/**
|
||||
Will be emitted if the user clicks to the map with the rigth mouse button.
|
||||
*/
|
||||
void contextMenuRequest( const QList< uint > & idList, QPoint viewPortPos );
|
||||
|
||||
/**
|
||||
Signal will be emitted if a mouse move is done.
|
||||
*/
|
||||
void mouseMovedEvent( int x, int y );
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool eventFilter(QObject*, QEvent*);
|
||||
|
||||
enum SelectionMode
|
||||
{
|
||||
NoSelection = 0x00,
|
||||
SingleSelection = 0x01,
|
||||
MultiSelection = 0x02,
|
||||
FrameSelection = 0x04
|
||||
}; // SelectionMode
|
||||
|
||||
Q_DECLARE_FLAGS(SelectionModes,SelectionMode)
|
||||
|
||||
EsriRuntimeQt::Map * _esriMap;
|
||||
QPoint _mouseMoveRefPos;
|
||||
QCursor _restoreMouseCursor;
|
||||
|
||||
static int _pickTolerance;
|
||||
SelectionModes _selectionMode;
|
||||
QList<uint> _selectedIdList; // List of selected object-ids. Is completly handled in selectionRequested()
|
||||
unsigned int _idConnectionCount; // counter to avoid multiple signals selectionRequest, see implementation of selectionRequested()
|
||||
bool _mousePanningActive; // is panning with mouse active
|
||||
|
||||
/**
|
||||
Find out which map objects are at given mouse position and emits the signal selectionRequest
|
||||
*/
|
||||
void selectionRequested( const QPoint & );
|
||||
|
||||
/**
|
||||
Find out which map objects are at given mouse position and emits the signal contextMenuRequest
|
||||
*/
|
||||
void pickRequested( const QPoint & );
|
||||
|
||||
/**
|
||||
Helper function to get all map objets at a given position
|
||||
@param pos position in window coordinates
|
||||
@param pickIdList List to store uid's of picked map objects. Don't use a local variable here because the picking is a asynchrone function
|
||||
@param append If true the uid's are appended at end of list. Otherwise the list will be cleared first.
|
||||
@param pickSignal Function pointer to signal to be emitted at end.
|
||||
*/
|
||||
void pickObjects( const QPoint & pos
|
||||
, QList<uint> & pickIdList
|
||||
, bool append
|
||||
, void (EventMouseNavigator::*pickSignal)(const QList< uint>&,QPoint) );
|
||||
|
||||
}; /* EventMouseNavigator */
|
||||
|
||||
|
||||
} } /* namespace SituationMap::RB */
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Declaration/Definition
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
|
||||
#include "gestures.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QEvent>
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
namespace SituationMap { namespace RB {
|
||||
|
||||
// TabGestureRecognizer
|
||||
|
||||
ApplyGestureRecognizer::ApplyGestureRecognizer() : QGestureRecognizer()
|
||||
{
|
||||
}
|
||||
|
||||
ApplyGestureRecognizer::~ApplyGestureRecognizer()
|
||||
{}
|
||||
|
||||
|
||||
QGesture * ApplyGestureRecognizer::create( QObject * target )
|
||||
{
|
||||
qDebug() << "ApplyGesture create";
|
||||
|
||||
if (target && target->isWidgetType())
|
||||
{
|
||||
((QWidget*)target)->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
}
|
||||
return new ApplyGesture();
|
||||
} // TabGestureRecognizer::create
|
||||
|
||||
|
||||
QGestureRecognizer::Result ApplyGestureRecognizer::recognize( QGesture * state, QObject* , QEvent * event)
|
||||
{
|
||||
ApplyGesture * q = static_cast<ApplyGesture*>(state);
|
||||
const QTouchEvent * ev = static_cast<const QTouchEvent*>(event);
|
||||
|
||||
QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture;
|
||||
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::TouchBegin:
|
||||
{
|
||||
qDebug() << "ApplyGesture begin";
|
||||
q->_position = ev->touchPoints().at(0).pos();
|
||||
q->setHotSpot(ev->touchPoints().at(0).screenPos());
|
||||
q->_tripleTouch = (ev->touchPoints().size() == 3);
|
||||
result = QGestureRecognizer::TriggerGesture;
|
||||
} break;
|
||||
|
||||
case QEvent::TouchUpdate:
|
||||
case QEvent::TouchEnd:
|
||||
{
|
||||
if (q->state() != Qt::NoGesture && ev->touchPoints().size() >= 1 && ev->touchPoints().size() <= 3)
|
||||
{
|
||||
if (ev->touchPoints().size() == 3) q->_tripleTouch = true;
|
||||
qDebug() << "ApplyGesture update _tripleTouch=" << q->_tripleTouch;
|
||||
QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
|
||||
QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
|
||||
enum { TapRadius = 40 };
|
||||
if (delta.manhattanLength() <= TapRadius)
|
||||
{
|
||||
if (event->type() == QEvent::TouchEnd)
|
||||
{
|
||||
result = (q->_tripleTouch) ? QGestureRecognizer::FinishGesture : QGestureRecognizer::CancelGesture;
|
||||
}
|
||||
else result = QGestureRecognizer::TriggerGesture;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::MouseButtonRelease:
|
||||
result = QGestureRecognizer::Ignore;
|
||||
break;
|
||||
default:
|
||||
result = QGestureRecognizer::Ignore;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
} // TabGestureRecognizer::recognize( QGesture * state, QObject * watched, QEvent * event)
|
||||
|
||||
|
||||
void ApplyGestureRecognizer::reset( QGesture * state )
|
||||
{
|
||||
ApplyGesture * q = static_cast<ApplyGesture*>(state);
|
||||
q->_tripleTouch = false;
|
||||
} // TabGestureRecognizer::reset( QGesture * gesture )
|
||||
|
||||
|
||||
|
||||
}} // namspaces
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Gesture recognition
|
||||
** $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 .........:
|
||||
**
|
||||
** 09.12.2015, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtWidgets/QGesture>
|
||||
#include <QtWidgets/QGestureRecognizer>
|
||||
|
||||
|
||||
namespace SituationMap { namespace RB
|
||||
{
|
||||
class ApplyGestureRecognizer : public QGestureRecognizer
|
||||
{
|
||||
public:
|
||||
ApplyGestureRecognizer();
|
||||
virtual ~ApplyGestureRecognizer();
|
||||
|
||||
QGesture * create( QObject * target ) override;
|
||||
QGestureRecognizer::Result recognize( QGesture * gesture, QObject * watched, QEvent * event) override;
|
||||
void reset( QGesture * gesture ) override;
|
||||
|
||||
}; // ApplyGestureRecognizer
|
||||
|
||||
|
||||
class ApplyGesture : public QGesture
|
||||
{
|
||||
friend class ApplyGestureRecognizer;
|
||||
|
||||
public:
|
||||
|
||||
ApplyGesture() = default;
|
||||
~ApplyGesture() = default;
|
||||
|
||||
ApplyGesture( const ApplyGesture & ) = delete;
|
||||
ApplyGesture & operator = ( const ApplyGesture & ) = delete;
|
||||
|
||||
QPointF position() const { return _position; }
|
||||
|
||||
private:
|
||||
|
||||
QPointF _position;
|
||||
bool _tripleTouch;
|
||||
}; // ApplyGesture
|
||||
|
||||
}} // namespaces
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Declaration/Definition
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QGraphicsScene>
|
||||
#include <QtWidgets/QGraphicsView>
|
||||
#include <QtWidgets/QGraphicsProxyWidget>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QTextEdit>
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
|
||||
#include "Map.h"
|
||||
#include "MapGraphicsView.h"
|
||||
#include "ArcGISLocalTiledLayer.h"
|
||||
|
||||
#include "event_mouse_navigator.h"
|
||||
|
||||
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
QApplication app ( argc, argv );
|
||||
|
||||
// under windows for ArcGIS 10.2.6 and higher
|
||||
#ifdef Q_OS_WIN
|
||||
QCoreApplication::setAttribute( Qt::AA_UseOpenGLES );
|
||||
#endif
|
||||
|
||||
QApplication::setApplicationName(QString("Esri - Map Touch Test"));
|
||||
|
||||
QWidget top;
|
||||
QHBoxLayout * layout = new QHBoxLayout( &top );
|
||||
QTextEdit * console = new QTextEdit( &top );
|
||||
EsriRuntimeQt::Map * map = new EsriRuntimeQt::Map();
|
||||
EsriRuntimeQt::MapGraphicsView * mapGraphicsView = EsriRuntimeQt::MapGraphicsView::create(map);
|
||||
|
||||
QString samplePath = EsriRuntimeQt::ArcGISRuntime::installDirectory();
|
||||
|
||||
samplePath.append("/sdk/samples/data/tpks/Topographic.tpk");
|
||||
|
||||
samplePath = QDir::toNativeSeparators(samplePath);
|
||||
|
||||
if (!QFileInfo::exists(samplePath))
|
||||
{
|
||||
qDebug() << "Load map from not existing file" << samplePath;
|
||||
}
|
||||
|
||||
EsriRuntimeQt::ArcGISLocalTiledLayer * geoMapBaseLayer = new EsriRuntimeQt::ArcGISLocalTiledLayer( samplePath, &top );
|
||||
geoMapBaseLayer -> setName( "Base Map Layer" );
|
||||
|
||||
QObject::connect( geoMapBaseLayer, &EsriRuntimeQt::ArcGISLocalTiledLayer::layerCreateError , []() { qDebug() << "Loading map failed!"; } );
|
||||
QObject::connect( geoMapBaseLayer, &EsriRuntimeQt::ArcGISLocalTiledLayer::layerCreateComplete, []() { qDebug() << "Loading map finished."; } );
|
||||
|
||||
map->setAnimationMode( EsriRuntimeQt::AnimationMode::NoAnimation );
|
||||
map->addLayer(geoMapBaseLayer);
|
||||
map->setWrapAroundEnabled(true);
|
||||
|
||||
map->grid()->setType( EsriRuntimeQt::GridType::Mgrs );
|
||||
map->grid()->setVisible(false);
|
||||
|
||||
mapGraphicsView -> setFixedSize( 600, 400 );
|
||||
|
||||
SituationMap::RB::EventMouseNavigator * eventDispatcher = new SituationMap::RB::EventMouseNavigator( mapGraphicsView->viewport(), map );
|
||||
layout->addWidget( mapGraphicsView );
|
||||
layout->addWidget( console );
|
||||
|
||||
top.show();
|
||||
|
||||
QPushButton * button = new QPushButton( QString("Touch or Click me"), nullptr ); // button must be toplevel widget
|
||||
QGraphicsProxyWidget * widgetProxy = mapGraphicsView->scene()->addWidget( button );
|
||||
|
||||
widgetProxy -> setPos( mapGraphicsView->mapToScene(250,200) );
|
||||
|
||||
QObject::connect( button, &QPushButton::clicked, [console]() { console->append(QString("Button has been clicked.\n")); });
|
||||
QObject::connect( button, &QPushButton::pressed, [console]() { console->append(QString("Button has been pressed.\n")); });
|
||||
|
||||
return app.exec();
|
||||
} // main (int argc, char* argv[])
|
||||
Reference in new issue
Block a user