1 /*************************************************************************** 2 qgsannotation.h 3 --------------- 4 begin : January 2017 5 copyright : (C) 2017 by Nyall Dawson 6 email : nyall dot dawson at gmail dot com 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef QGSANNOTATION_H 19 #define QGSANNOTATION_H 20 21 #include "qgis_core.h" 22 #include "qgis.h" 23 #include "qgspointxy.h" 24 #include "qgscoordinatereferencesystem.h" 25 #include "qgsmargins.h" 26 #include "qgsmaplayer.h" 27 #include "qgsfeature.h" 28 29 #include <QPointer> 30 31 class QgsRenderContext; 32 class QgsMarkerSymbol; 33 class QgsFillSymbol; 34 35 /** 36 * \ingroup core 37 * \class QgsAnnotation 38 * 39 * \brief Abstract base class for annotation items which are drawn over a map. 40 * 41 * QgsAnnotation is an abstract base class for map annotation items. These annotations can be 42 * drawn within a map, and have either a fixed map position (retrieved using mapPosition()) 43 * or are placed relative to the map's frame (retrieved using relativePosition()). 44 * Annotations with a fixed map position also have a corresponding 45 * QgsCoordinateReferenceSystem, which can be determined by calling mapPositionCrs(). 46 * 47 * Derived classes should implement their custom painting routines within 48 * a renderAnnotation() override. 49 * 50 * \since QGIS 3.0 51 */ 52 53 class CORE_EXPORT QgsAnnotation : public QObject 54 { 55 56 #ifdef SIP_RUN 57 SIP_CONVERT_TO_SUBCLASS_CODE 58 if ( dynamic_cast< QgsTextAnnotation * >( sipCpp ) ) 59 sipType = sipType_QgsTextAnnotation; 60 else if ( dynamic_cast< QgsSvgAnnotation * >( sipCpp ) ) 61 sipType = sipType_QgsSvgAnnotation; 62 else if ( dynamic_cast< QgsHtmlAnnotation * >( sipCpp ) ) 63 sipType = sipType_QgsHtmlAnnotation; 64 else 65 sipType = NULL; 66 SIP_END 67 #endif 68 69 70 Q_OBJECT 71 Q_PROPERTY( bool visible READ isVisible WRITE setVisible ) 72 Q_PROPERTY( bool hasFixedMapPosition READ hasFixedMapPosition WRITE setHasFixedMapPosition ) 73 Q_PROPERTY( QgsPointXY mapPosition READ mapPosition WRITE setMapPosition ) 74 Q_PROPERTY( QSizeF frameSize READ frameSize WRITE setFrameSize ) 75 76 public: 77 78 /** 79 * Constructor for QgsAnnotation. 80 */ 81 QgsAnnotation( QObject *parent SIP_TRANSFERTHIS = nullptr ); 82 83 ~QgsAnnotation() override; 84 85 /** 86 * Clones the annotation, returning a new copy of the annotation 87 * reflecting the annotation's current state. 88 */ 89 virtual QgsAnnotation *clone() const = 0 SIP_FACTORY; 90 91 /** 92 * Returns TRUE if the annotation is visible and should be rendered. 93 * \see setVisible() 94 */ isVisible()95 bool isVisible() const { return mVisible; } 96 97 /** 98 * Sets whether the annotation is visible and should be rendered. 99 * \see isVisible() 100 */ 101 void setVisible( bool visible ); 102 103 /** 104 * Returns TRUE if the annotation is attached to a fixed map position, or 105 * FALSE if the annotation uses a position relative to the current map 106 * extent. 107 * \see setHasFixedMapPosition() 108 * \see mapPosition() 109 * \see relativePosition() 110 */ hasFixedMapPosition()111 bool hasFixedMapPosition() const { return mHasFixedMapPosition; } 112 113 /** 114 * Sets whether the annotation is attached to a fixed map position, or 115 * uses a position relative to the current map extent. 116 * \see hasFixedMapPosition() 117 */ 118 void setHasFixedMapPosition( bool fixed ); 119 120 /** 121 * Returns the map position of the annotation, if it is attached to a fixed map 122 * position. 123 * \see setMapPosition() 124 * \see hasFixedMapPosition() 125 * \see mapPositionCrs() 126 */ mapPosition()127 QgsPointXY mapPosition() const { return mMapPosition; } 128 129 /** 130 * Sets the map position of the annotation, if it is attached to a fixed map 131 * position. 132 * \see mapPosition() 133 */ 134 void setMapPosition( const QgsPointXY &position ); 135 136 /** 137 * Returns the CRS of the map position, or an invalid CRS if the annotation does 138 * not have a fixed map position. 139 * \see setMapPositionCrs() 140 */ mapPositionCrs()141 QgsCoordinateReferenceSystem mapPositionCrs() const { return mMapPositionCrs; } 142 143 /** 144 * Sets the CRS of the map position. 145 * \see mapPositionCrs() 146 */ 147 void setMapPositionCrs( const QgsCoordinateReferenceSystem &crs ); 148 149 /** 150 * Returns the relative position of the annotation, if it is not attached to a fixed map 151 * position. The coordinates in the return point should be between 0 and 1, and represent 152 * the relative percentage for the position compared to the map width and height. 153 * \see setRelativePosition() 154 */ relativePosition()155 QPointF relativePosition() const { return mRelativePosition; } 156 157 /** 158 * Sets the relative position of the annotation, if it is not attached to a fixed map 159 * position. The coordinates in the return point should be between 0 and 1, and represent 160 * the relative percentage for the position compared to the map width and height. 161 * \see relativePosition() 162 */ 163 void setRelativePosition( QPointF position ); 164 165 /** 166 * Sets the annotation's frame's offset (in pixels) from the mapPosition() reference point. 167 * \see frameOffsetFromReferencePoint() 168 * \deprecated use setFrameOffsetFromReferencePointMm() instead 169 */ 170 Q_DECL_DEPRECATED void setFrameOffsetFromReferencePoint( QPointF offset ) SIP_DEPRECATED; 171 172 /** 173 * Returns the annotation's frame's offset (in pixels) from the mapPosition() reference point. 174 * \see setFrameOffsetFromReferencePoint() 175 * \deprecated use frameOffsetFromReferencePointMm() instead 176 */ 177 Q_DECL_DEPRECATED QPointF frameOffsetFromReferencePoint() const SIP_DEPRECATED; 178 179 /** 180 * Sets the annotation's frame's offset (in millimeters) from the mapPosition() reference point. 181 * \see frameOffsetFromReferencePointMm() 182 * \since QGIS 3.4.8 183 */ 184 void setFrameOffsetFromReferencePointMm( QPointF offset ); 185 186 /** 187 * Returns the annotation's frame's offset (in millimeters) from the mapPosition() reference point. 188 * \see setFrameOffsetFromReferencePointMm() 189 * \since QGIS 3.4.8 190 */ frameOffsetFromReferencePointMm()191 QPointF frameOffsetFromReferencePointMm() const { return mOffsetFromReferencePoint; } 192 193 /** 194 * Sets the size (in pixels) of the annotation's frame (the main area in which 195 * the annotation's content is drawn). 196 * \see frameSize() 197 * \deprecated use setFrameSizeMm() instead 198 */ 199 Q_DECL_DEPRECATED void setFrameSize( QSizeF size ) SIP_DEPRECATED; 200 201 /** 202 * Returns the size (in pixels) of the annotation's frame (the main area in which 203 * the annotation's content is drawn). 204 * \see setFrameSize() 205 * \deprecated use frameSizeMm() instead 206 */ 207 Q_DECL_DEPRECATED QSizeF frameSize() const SIP_DEPRECATED; 208 209 /** 210 * Sets the size (in millimeters) of the annotation's frame (the main area in which 211 * the annotation's content is drawn). 212 * \see frameSizeMm() 213 * \since QGIS 3.4.8 214 */ 215 void setFrameSizeMm( QSizeF size ); 216 217 /** 218 * Returns the size (in millimeters) of the annotation's frame (the main area in which 219 * the annotation's content is drawn). 220 * \see setFrameSizeMm() 221 * \since QGIS 3.4.8 222 */ frameSizeMm()223 QSizeF frameSizeMm() const { return mFrameSize; } 224 225 /** 226 * Sets the margins (in millimeters) between the outside of the frame and the annotation 227 * content. 228 * \see contentsMargin() 229 */ 230 void setContentsMargin( const QgsMargins &margins ); 231 232 /** 233 * Returns the margins (in millimeters) between the outside of the frame and the annotation 234 * content. 235 * \see setContentsMargin() 236 */ contentsMargin()237 QgsMargins contentsMargin() const { return mContentsMargins; } 238 239 /** 240 * Sets the fill symbol used for rendering the annotation frame. Ownership 241 * of the symbol is transferred to the annotation. 242 * \see fillSymbol() 243 */ 244 void setFillSymbol( QgsFillSymbol *symbol SIP_TRANSFER ); 245 246 /** 247 * Returns the symbol that is used for rendering the annotation frame. 248 * \see setFillSymbol() 249 */ 250 QgsFillSymbol *fillSymbol() const; 251 252 /** 253 * Renders the annotation to a target render context. 254 */ 255 void render( QgsRenderContext &context ) const; 256 257 /** 258 * Writes the annotation state to a DOM element. Derived classes should 259 * call _writeXml() within their implementation of this method. 260 * \see readXml() 261 * \see _writeXml() 262 */ 263 virtual void writeXml( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context ) const = 0; 264 265 /** 266 * Restores the annotation's state from a DOM element. Derived classes should 267 * call _readXml() within their implementation of this method. 268 * \see writeXml() 269 * \see _readXml() 270 */ 271 virtual void readXml( const QDomElement &itemElem, const QgsReadWriteContext &context ) = 0; 272 273 /** 274 * Sets the symbol that is drawn at the annotation's map position. Ownership 275 * of the symbol is transferred to the annotation. 276 * \see markerSymbol() 277 */ 278 void setMarkerSymbol( QgsMarkerSymbol *symbol SIP_TRANSFER ); 279 280 /** 281 * Returns the symbol that is drawn at the annotation's map position. 282 * \see setMarkerSymbol() 283 */ markerSymbol()284 QgsMarkerSymbol *markerSymbol() const { return mMarkerSymbol.get(); } 285 286 /** 287 * Returns the map layer associated with the annotation. Annotations can be 288 * associated with a map layer if their visibility should be synchronized 289 * with the layer's visibility. 290 * \see setMapLayer() 291 */ mapLayer()292 QgsMapLayer *mapLayer() const { return mMapLayer.data(); } 293 294 /** 295 * Sets the map layer associated with the annotation. Annotations can be 296 * associated with a map layer if their visibility should be synchronized 297 * with the layer's visibility. 298 * \see mapLayer() 299 */ 300 void setMapLayer( QgsMapLayer *layer ); 301 302 /** 303 * Returns the feature associated with the annotation, or an invalid 304 * feature if none has been set. 305 * \see setAssociatedFeature() 306 */ associatedFeature()307 QgsFeature associatedFeature() const { return mFeature; } 308 309 /** 310 * Sets the feature associated with the annotation. 311 * \see associatedFeature() 312 */ 313 virtual void setAssociatedFeature( const QgsFeature &feature ); 314 315 /** 316 * Accepts the specified style entity \a visitor, causing it to visit all style entities associated 317 * within the annotation. 318 * 319 * Returns TRUE if the visitor should continue visiting other objects, or FALSE if visiting 320 * should be canceled. 321 * 322 * \since QGIS 3.10 323 */ 324 virtual bool accept( QgsStyleEntityVisitorInterface *visitor ) const; 325 326 signals: 327 328 //! Emitted whenever the annotation's appearance changes 329 void appearanceChanged(); 330 331 /** 332 * Emitted when the annotation's position has changed and items need 333 * to be moved to reflect this. 334 */ 335 void moved(); 336 337 /** 338 * Emitted when the map layer associated with the annotation changes. 339 */ 340 void mapLayerChanged(); 341 342 protected: 343 344 /** 345 * Renders the annotation's contents to a target /a context at the specified /a size. 346 * Derived classes should implement their custom annotation drawing logic here. 347 */ 348 virtual void renderAnnotation( QgsRenderContext &context, QSizeF size ) const = 0; 349 350 /** 351 * Returns the minimum frame size for the annotation. Subclasses should implement this if they 352 * cannot be resized smaller than a certain minimum size. 353 */ 354 virtual QSizeF minimumFrameSize() const; 355 356 /** 357 * Writes common annotation properties to a DOM element. 358 * This method should be called from subclasses in their writeXml method. 359 * \see writeXml() 360 * \see _readXml() 361 */ 362 void _writeXml( QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; 363 364 /** 365 * Reads common annotation properties from a DOM element. 366 * This method should be called from subclasses in their readXml method. 367 * \see readXml() 368 * \see _writeXml() 369 */ 370 void _readXml( const QDomElement &annotationElem, const QgsReadWriteContext &context ); 371 372 /** 373 * Copies common annotation properties to the \a targe 374 * annotation. 375 * Can be used within QgsAnnotation::clone() implementations 376 * to assist with creating copies. 377 */ 378 void copyCommonProperties( QgsAnnotation *target ) const; 379 380 private: 381 382 //! Draws the annotation frame to a destination painter 383 void drawFrame( QgsRenderContext &context ) const; 384 385 //! Draws the map position marker symbol to a destination painter 386 void drawMarkerSymbol( QgsRenderContext &context ) const; 387 388 bool mVisible = true; 389 390 //! True if the item stays at the same map position, FALSE if the item stays on same screen position 391 bool mHasFixedMapPosition = true; 392 393 //! Map position (for fixed position items) 394 QgsPointXY mMapPosition; 395 396 //! CRS of the map position 397 QgsCoordinateReferenceSystem mMapPositionCrs; 398 399 //! Relative position (for non-fixed items) (0-1) 400 QPointF mRelativePosition; 401 402 //! Describes the shift of the item content box to the reference point in mm 403 QPointF mOffsetFromReferencePoint = QPointF( 13, -13 ); 404 405 //! Size of the frame in mm (without balloon) 406 QSizeF mFrameSize; 407 408 //! Point symbol that is to be drawn at the map reference location 409 std::unique_ptr<QgsMarkerSymbol> mMarkerSymbol; 410 411 QgsMargins mContentsMargins; 412 413 //! Fill symbol used for drawing annotation 414 std::unique_ptr<QgsFillSymbol> mFillSymbol; 415 416 //! Associated layer (or NULLPTR if not attached to a layer) 417 QgsWeakMapLayerPointer mMapLayer; 418 419 //! Associated feature, or invalid feature if no feature associated 420 QgsFeature mFeature; 421 422 //! Roughly 10 pixels at 96 dpi, to match earlier version rendering 423 double mSegmentPointWidthMm = 2.64; 424 425 }; 426 427 #endif // QGSANNOTATION_H 428 429