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

501 lines
20 KiB
Objective-C
Executable File

/**
**
** @RDE_HEADER@
** Definition of base class for rubberbands
** $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 .........:
**
** 27.03.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "event_dispatcher.h"
#include "event_delegater.h"
#include <Map/map.h>
#include <Common/ref_pointer.h>
#include <QtCore/QList>
#include <QtCore/QObject>
#include <QtCore/QPointer>
#include <QtGui/QColor>
#include <memory>
namespace Esri {
namespace ArcGISRuntime {
class MapGraphicsView;
class Point;
} }
namespace SituationMap
{
/**
Namespace for all rubberband stuff (is part of namespace SituationMap)
*/
namespace RB
{
/**
*/
enum class CoordinateSystem
{
Map,
Geo
};
/**
@class RubberbandBase rubberband_base.h
@brief Base class of all Rubberbands
Rubberbands are used to create or modifiy geometries like lines, circles, polygons etc. by processing
Qt input events like keyboard and mouse events. To create a rubberband the RubberbandFactory has to be used.
At end of rubberband processing the signal \c abort or\c apply are emitted. To delete the rubberband the
function deleteMySelf must be called. To use the delete operator is dangerous because at end of signal
processing some program code may be performed.
Example to how to use rubberband:
@code
SituationMap::Map & map = ...
const RubberbandFactory & rubberbandFactory = map.rubberbandFactory();
RubberbandPointFeature * rubberband = rubberbandFactory.create<RubberbandPointFeature>();
if (rubberband != nullptr)
{
QObject::connect( rubberband, &SiMapRubBnd::Rubberband::apply, [=](SiMapRubBnd::Rubberband * rubberband )
{
// rubberband has finished input
if (rubberband)
{
const QVector<QPointF> & vertexList = rubberband->coordinateVector();
// do something with vertexList
rubberband->deleteMySelf(); // notice don't call here delete rubberband directly !!!
}
} );
QObject::connect( rubberband, &SiMapRubBnd::Rubberband::abort, this, [=](SiMapRubBnd::Rubberband * rubberband )
{
// Rubberband has been aborted by user
if (rubberband)
{
rubberband->deleteMySelf(); // notice don't call here delete rubberband directly !!!
}
} );
}
@endcode
Following keyboard commands are available in active rubberbands:
| Key | Modifier | Funktion |
| :----: |:-------: | :--------------------------------------------------------------------------- |
| Esc | | Rubberband abbrechen |
| Return | | Rubberband abschließen und Eingabe übernehmen wenn möglich, sonst Abbruch |
| Left | | Selektierten Handle (Punkt,Frame) um 1 Pixel nach links schieben |
| Right | | Selektierten Handle (Punkt,Frame) um 1 Pixel nach rechts schieben |
| Up | | Selektierten Handle (Punkt,Frame) um 1 Pixel nach oben schieben |
| Down | | Selektierten Handle (Punkt,Frame) um 1 Pixel nach unten schieben |
| Left | Shift | Selektierten Handle (Punkt,Frame) um 10 Pixel nach links schieben |
| Right | Shift | Selektierten Handle (Punkt,Frame) um 10 Pixel nach rechts schieben |
| Up | Shift | Selektierten Handle (Punkt,Frame) um 10 Pixel nach oben schieben |
| Down | Shift | Selektierten Handle (Punkt,Frame) um 10 Pixel nach unten schieben |
@see EventDispatcher
@see Rubberband, RubberbandPointFeature, RubberbandPointCluster, RubberbandMultiPointFeature, RubberbandRectangle, RubberbandEllipse, RubberbandCorridor, RubberbandArrow
Rubberband3D, RubberbandPointFeature3D, RubberbandMultiPointFeature3D
*/
class SITUATIONMAP_EXPORT RubberbandBase : public QObject, public EventDispatcher::EventActionInterface
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Because class EventDispatcher::EventActionInterface is a pure virtual interface function the classic way of declaration would be
*
* SITUATIONMAP_EXPORT Rubberband : public QObject, public virtual EventDispatcher::EventActionInterface
*
* But with Visual Studio 2013 virtual inheritance combined with constructor delegation doesn't work and may crash the program. In
* this case the virtual inheritance of EventActionInterface isn't need because in the derived classes multiple inheritance will
* not be used.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
public:
/**
Constructs a Rubberband for a situation map. Use \c RubberbandFactor to create a rubberband.
In case of the user actions the autoDelete mechanism can be used to delete the rubberband. Sometimes
the application wants to finish a running rubberband. This can be done by calling \c deleteMySelf. The
rubberband will be destroyed also automatically if the parent QObject or the map (see
SituationMap::Map::beginDestroy signal) will be destroyed.
@param map Pointer to SituationMap::Map
@param parent Pointer to QObject to use as parent.
@isActive If set to false the Rubberband is not active and have to be actived to start the input.
@see RubberbandFactory
*/
RubberbandBase( SituationMap::Map * map, QObject * parent, bool isActive = true );
~RubberbandBase();
/** @} */
/**
Activate rubberband if it has been created with \c isActive = false.
*/
void activate();
/**
Provides a list of active rubberbands for a situation map.
*/
static QList<RubberbandBase*> activeRubberbands( SituationMap::Map * map );
/**
Delete active rubberbands for a situation map.
*/
static void deleteAllActiveRubberbands( SituationMap::Map * map );
/**
Use deleteMySelft instead of delete operator to avoid dangling this pointerin Qt signal processing. It calls delete this; later on.
*/
void deleteMySelf();
/**
If setting auto delete flag to true the delete will be done automatically after sending signal abort or apply.
The default value of auto delete flag is false.
@{
*/
inline void setAutoDelete(bool on) { _autoDelete = on; }
inline bool autoDelete() const { return _autoDelete; }
/** @} */
/**
Returns true if the rubberband is already alive. Should be tested after creation of a rubberband because it is
possibled to create not living rubberbands, e.g. a rubberband was create twice and the first one has not finished
*/
inline bool rubberbandIsAlive() const { return !_viewPortEventDispatcher.isNull(); }
/** A single user action step has finished. Interim results can be used to show a preview now.
*/
void userActionFinished() override { emit interimResultsChanged(this); }
/**
@name ColorSettings Methodes to define visual behaviour of rubberband
@{
*/
inline void setDrawColor (const QColor & col ) { _drawColor = col; update(); } ///< set color for general drawing
inline void setFillColor (const QColor & col ) { _fillColor = col; update(); } ///< set color for general filling
inline void setHandleDrawColor (const QColor & col ) { _handleDrawColor = col; update(); } ///< set color for drawing handles
inline void setHandleFillColor (const QColor & col ) { _handleFillColor = col; update(); } ///< set color for filling handles
inline void setHandleSelectionColor(const QColor & col ) { _handleSelectionColor = col; update(); } ///< set handle selection color
inline void setFrameColor (const QColor & col ) { _frameColor = col; update(); } ///< set frame handle outline color
inline void setFrameFillColor (const QColor & col ) { _frameFillColor = col; update(); } ///< set frame handle fill color
inline void setFrameHandleMargin (int margin ) { _frameHandleMargin = margin; update(); } ///< set margin of frame in pixel
inline void setPickingRatio (unsigned int size ) { _pickingRatio = size; update(); } ///< set size of point handles
inline void setLineHandleWidth (unsigned int width ) { _lineHandleWidth = width; update(); } ///< set width of line handles
inline const QColor getDrawColor () const { return _drawColor; } ///< get color for general drawing
inline const QColor getFillColor () const { return _fillColor; } ///< get color for general filling
inline const QColor getHandleDrawColor() const { return _handleDrawColor; } ///< get color for drawing handles
inline const QColor getHandleFillColor() const { return _handleFillColor; } ///< get color for filling handles
inline const QColor getHandleSelectionColor() const { return _handleSelectionColor; } ///< get handle selection color
inline const QColor getFrameColor() const { return _frameColor; } ///< get frame handle outline color
inline const QColor getFrameFillColor() const { return _frameFillColor; } ///< get frame handle fill color
inline int getFrameHandleMargin() const { return _frameHandleMargin; } ///< get margin of frame in pixel
inline unsigned int getPickingRatio() const { return _pickingRatio; } ///< get size of point handles
/** @} */
bool applyAndEndAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool abortAction ( AbstractEventDispatcher * causer, int x, int y ) override;
/**
@name Set icons for rubberband buttons
In case of the application doesn't use the default rubberband icons other icons can be set with the setIcon functions. This redefine
of the button icons have to be done before creating a rubberband.
@{
*/
static void setIconApply( const QPixmap & );
static void setIconAbort( const QPixmap & );
static void setIconUndo ( const QPixmap & );
static void resetIconsToDefault();
/** @} */
/**
Start Rubberband mouse input automatically by program
*/
bool autoSelectAction( int x, int y );
/**
If set to true the rubberband will send apply signal after leaving construction state and ends
otherwise it continues in modification state. Default value is true.
*/
inline void enableFinishAfterConstruction(bool flag) { _finishAfterConstruction = flag; }
/**
Defines fixed widget position of rubberband button box
*/
void setFixedButtonBoxPosition( QPoint widgetPos );
/**
Undefines fixed widget position. The rubberband button box will be placed at the bottom right coner of
the rubberbands bounding box.
*/
void unsetFixedButtonBoxPosition();
/**
Returns true if a fixed widget position of rubberband button box is used.
*/
bool isButtonBoxPositionFixed();
/**
@name EventHandlerInterface Methodes of AbstractEventDispatcher::EventActionInterface
The interface between EventDispatcher and Rubberband are defined in class AbstractEventDispatcher.
To Implement the interface these methodes have to be override again in the derived classes of the Rubberband class. */
/**
@{
*/
bool buttonPositionAction ( AbstractEventDispatcher * causer, int x, int y ) override;
void unlinkEventDispatcher ( AbstractEventDispatcher * causer ) override;
/** @} */
/**
Returns true if the coordinates are valid elsewise false
*/
virtual bool coordinatesAreValid() const { return true; }
/**
Returns count of coordinates
*/
virtual unsigned int coordinateCount() const = 0;
/**
Returns constructed or modified coordinates
@param cs Defines the coordinate system of returned coordinates.
*/
virtual QVector<QPointF> coordinateVector( CoordinateSystem cs = CoordinateSystem::Geo ) const = 0;
/**
Returns a single coordinate from rubberbands coordinate list
@param idx index of coordinate
@param cs Defines the coordinate system of returned coordinate.
*/
virtual QPointF singleCoordinate( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const = 0;
/**
Sets coordinates to modify to internal coordinate list
@param pntList List of coordinates to modify
@param cs Defines the coordinate system of input coordinates.
*/
virtual void setCoordinateVector( const QVector<QPointF> & pntList, CoordinateSystem cs = CoordinateSystem::Geo ) = 0;
/**
Set user defined informations to this rubberband
*/
inline void setUserData(void * p)
{
_userData = p;
}
/**
returns the user defined informations, which are set with methode userData(void*)
*/
inline void * userData() { return _userData; }
/**
Draw rubberband manually by calling the update function. In general it is not neccessary to call draw function.
But in some cases, for example the color setting functions, the graphic view update will not be done automatically.
Here calling draw forces an update of graphic view.
*/
inline void draw() { update(); }
/**
Sets call back function to realize an external update. The updateFunctor should return false to abort update process. In other case it have to return true.
*/
void installExternalUpdate(const std::function<bool(RubberbandBase*)> & updateFunctor);
/**
Returns true if there is a active rubberband on map.
@param map Pointer to map
*/
static bool isRubberbandActive( SituationMap::Map * map );
/**
Abort all active rubberbands on map.
@param map Pointer to map
*/
static void abortActiveRubberbands( SituationMap::Map * map );
protected:
Q_REQUIRED_RESULT QPointF projectCoordinateToMap( CoordinateSystem cs, const QPointF &loc ) const;
Q_REQUIRED_RESULT QPointF projectCoordinateFromMap( CoordinateSystem cs, const QPointF & loc ) const;
Q_REQUIRED_RESULT QPointF projectCoordinateFromMap( CoordinateSystem cs, const Esri::ArcGISRuntime::Point & loc ) const;
inline void doAutoDelete() { if (_autoDelete) deleteMySelf(); }
void updateButtonPosition();
QPointF pixel2ScenePosition( int x, int y ) const;
virtual void update() = 0;
void externalUpdate();
/*
Forward declaration of internal container class for member variables. The derived classes of Rubberband
often have also a declaration of InternalData for there own internal members.
*/
class BaseInternalData;
BaseInternalData *_baseInternal;
QColor _drawColor;
QColor _fillColor;
QColor _handleDrawColor;
QColor _handleFillColor;
QColor _handleSelectionColor;
QColor _frameColor;
QColor _frameFillColor;
QColor _frameSelectionColor;
int _frameHandleMargin;
unsigned int _lineHandleWidth;
unsigned int _pickingRatio;
bool _finishAfterConstruction;
bool _autoDelete;
QPointer<EventDispatcher> _viewPortEventDispatcher;
QPointer<EventDelegater> _windowEventDispatcher;
virtual QRectF sceneBbox() const = 0;
virtual void activateButtons();
virtual void deactivateButtons();
virtual void adjustButtons();
virtual void applyButtonClicked();
virtual void cancelButtonClicked();
virtual void undoButtonClicked();
protected slots:
void onDo_applyButtonClicked() { applyButtonClicked(); }
void onDo_cancelButtonClicked() { cancelButtonClicked(); }
void onDo_undoButtonClicked() { undoButtonClicked(); }
void onDo_updateButtonFixCoordinates();
private:
void * _userData;
friend class RubberbandFactory;
static void * operator new(size_t);
/**
The function \c allowMultipleRubberbands set a flag to allow new to create more than one rubberband
per situation map for the next new operator call. The function is used in class RubberbandFactory. The
value will be resetted to \c false at end of new operator.
*/
static void allowMultipleRubberbands( bool ok );
/**
The function \c currentFactoryMap defines the calling situation map for the next new operator call. The
function is used in class RubberbandFactory.The value will be resetted to \c nullptr at end of new operator.
*/
static void currentFactoryMap( SituationMap::Map * map );
signals:
/**
The abort signal will be emitted, when the abortAction has been called by one of the attached event handlers.
Before emtting the signal the event handler are closed and deleted. To avoid memory leaks the application has to
ensure that the delete function is called for this rubberband. See also example code at beginning.
@param rbnd pointer to this Rubberband
*/
void abort( RubberbandBase * rbnd );
/**
The apply signal will be emitted, when the applyAndEndAction has been called by one of the attached event handler. The connected slot can now
read the geometry information. Before emtting the signal the event handler are closed and deleted.To avoid memory leaks the application has to
ensure that the delete function is called for this rubberband. See also example code at beginning.
@param rbnd pointer to this Rubberband.
*/
void apply( RubberbandBase * rbnd );
/**
The finished signal will be emitted, when the rubberband is going to terminate and all user actions are done.
@param rbnd pointer to this Rubberband.
*/
void finished( RubberbandBase * rbnd );
/**
The coordinatesChanged signal will be emitted , when the user has changed, removed or added coordinates. Can be used to implement
a preview of interim results.
*/
void interimResultsChanged( RubberbandBase * rbnd );
}; /* Rubberband */
} } /* namespace SituationMap::RB */