Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgspainteffect.h 3 : : ---------------- 4 : : begin : December 2014 5 : : copyright : (C) 2014 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 : : #ifndef QGSPAINTEFFECT_H 18 : : #define QGSPAINTEFFECT_H 19 : : 20 : : #include "qgis_core.h" 21 : : #include "qgis_sip.h" 22 : : #include "qgssymbollayer.h" 23 : : #include <QPainter> 24 : : #include <QDomDocument> 25 : : #include <QDomElement> 26 : : 27 : : class QgsRenderContext; 28 : : 29 : : /** 30 : : * \ingroup core 31 : : * \class QgsPaintEffect 32 : : * \brief Base class for visual effects which can be applied to QPicture drawings 33 : : * 34 : : * QgsPaintEffect objects can be used to modify QPicture drawings prior to rendering 35 : : * them with a QPainter operation. There are two methods for drawing using an effect, 36 : : * either drawing a picture directly, or by intercepting drawing operations to a 37 : : * render context. 38 : : * 39 : : * To directly draw a picture, use the render() method with a source 40 : : * QPicture and destination render context. 41 : : * 42 : : * Intercepting drawing operations to a render context is achieved by first calling 43 : : * the begin() method, passing a render context. Any drawing operations 44 : : * performed on the render context will not directly affect the context's paint 45 : : * device. When the drawing operations have been completed, call the end() 46 : : * method. This will perform the paint effect on the intercepted drawing operations 47 : : * and render the result to the render context's paint device. 48 : : * 49 : : * \see QgsPaintEffectRegistry 50 : : * \since QGIS 2.9 51 : : */ 52 : : 53 : : class CORE_EXPORT QgsPaintEffect SIP_NODEFAULTCTORS 54 : : { 55 : : 56 : : #ifdef SIP_RUN 57 : : SIP_CONVERT_TO_SUBCLASS_CODE 58 : : if ( sipCpp->type() == "drawSource" && dynamic_cast<QgsDrawSourceEffect *>( sipCpp ) != NULL ) 59 : : { 60 : : sipType = sipType_QgsDrawSourceEffect; 61 : : } 62 : : else if ( sipCpp->type() == "effectStack" && dynamic_cast<QgsEffectStack *>( sipCpp ) != NULL ) 63 : : { 64 : : sipType = sipType_QgsEffectStack; 65 : : } 66 : : else if ( sipCpp->type() == "blur" && dynamic_cast<QgsBlurEffect *>( sipCpp ) != NULL ) 67 : : { 68 : : sipType = sipType_QgsBlurEffect; 69 : : } 70 : : else if ( sipCpp->type() == "dropShadow" && dynamic_cast<QgsDropShadowEffect *>( sipCpp ) != NULL ) 71 : : { 72 : : sipType = sipType_QgsDropShadowEffect; 73 : : } 74 : : else if ( sipCpp->type() == "outerGlow" && dynamic_cast<QgsOuterGlowEffect *>( sipCpp ) != NULL ) 75 : : { 76 : : sipType = sipType_QgsOuterGlowEffect; 77 : : } 78 : : else if ( sipCpp->type() == "innerGlow" && dynamic_cast<QgsInnerGlowEffect *>( sipCpp ) != NULL ) 79 : : { 80 : : sipType = sipType_QgsInnerGlowEffect; 81 : : } 82 : : else if ( sipCpp->type() == "transform" && dynamic_cast<QgsTransformEffect *>( sipCpp ) != NULL ) 83 : : { 84 : : sipType = sipType_QgsTransformEffect; 85 : : } 86 : : else if ( sipCpp->type() == "color" && dynamic_cast<QgsColorEffect *>( sipCpp ) != NULL ) 87 : : { 88 : : sipType = sipType_QgsColorEffect; 89 : : } 90 : : else 91 : : { 92 : : sipType = 0; 93 : : } 94 : : SIP_END 95 : : #endif 96 : : 97 : : public: 98 : : 99 : : /** 100 : : * Drawing modes for effects. These modes are used only when effects are 101 : : * drawn as part of an effects stack 102 : : * \see QgsEffectStack 103 : : */ 104 : : enum DrawMode 105 : : { 106 : : Modifier, //!< The result of the effect is not rendered, but is passed on to following effects in the stack 107 : : Render, //!< The result of the effect is rendered on the destination, but does not affect subsequent effects in the stack 108 : : ModifyAndRender //!< The result of the effect is both rendered and passed on to subsequent effects in the stack 109 : : }; 110 : : 111 : : /** 112 : : * Constructor for QgsPaintEffect. 113 : : */ 114 : 713 : QgsPaintEffect() = default; 115 : : 116 : : QgsPaintEffect( const QgsPaintEffect &other ); 117 : : virtual ~QgsPaintEffect(); 118 : : 119 : : /** 120 : : * Returns the effect type. 121 : : * \returns unique string representation of the effect type 122 : : */ 123 : : virtual QString type() const = 0; 124 : : 125 : : /** 126 : : * Duplicates an effect by creating a deep copy of the effect 127 : : * \returns clone of paint effect 128 : : */ 129 : : virtual QgsPaintEffect *clone() const = 0 SIP_FACTORY; 130 : : 131 : : /** 132 : : * Returns the properties describing the paint effect encoded in a 133 : : * string format. 134 : : * \returns string map of properties, in the form property key, value 135 : : * \see readProperties 136 : : * \see saveProperties 137 : : */ 138 : : virtual QVariantMap properties() const = 0; 139 : : 140 : : /** 141 : : * Reads a string map of an effect's properties and restores the effect 142 : : * to the state described by the properties map. 143 : : * \param props effect properties encoded in a string map 144 : : * \see properties 145 : : */ 146 : : virtual void readProperties( const QVariantMap &props ) = 0; 147 : : 148 : : /** 149 : : * Saves the current state of the effect to a DOM element. The default 150 : : * behavior is to save the properties string map returned by 151 : : * properties(). 152 : : * \param doc destination DOM document 153 : : * \param element destination DOM element 154 : : * \returns TRUE if save was successful 155 : : * \see readProperties 156 : : */ 157 : : virtual bool saveProperties( QDomDocument &doc, QDomElement &element ) const; 158 : : 159 : : /** 160 : : * Restores the effect to the state described by a DOM element. 161 : : * \param element DOM element describing an effect's state 162 : : * \returns TRUE if read was successful 163 : : * \see saveProperties 164 : : */ 165 : : virtual bool readProperties( const QDomElement &element ); 166 : : 167 : : /** 168 : : * Renders a picture using the effect. 169 : : * \param picture source QPicture to render 170 : : * \param context destination render context 171 : : * \see begin 172 : : */ 173 : : virtual void render( QPicture &picture, QgsRenderContext &context ); 174 : : 175 : : /** 176 : : * Begins intercepting paint operations to a render context. When the corresponding 177 : : * end() member is called all intercepted paint operations will be 178 : : * drawn to the render context after being modified by the effect. 179 : : * \param context destination render context 180 : : * \see end 181 : : * \see render 182 : : */ 183 : : virtual void begin( QgsRenderContext &context ); 184 : : 185 : : /** 186 : : * Ends interception of paint operations to a render context, and draws the result 187 : : * to the render context after being modified by the effect. 188 : : * \param context destination render context 189 : : * \see begin 190 : : */ 191 : : virtual void end( QgsRenderContext &context ); 192 : : 193 : : /** 194 : : * Returns whether the effect is enabled 195 : : * \returns TRUE if effect is enabled 196 : : * \see setEnabled 197 : : */ 198 : 100 : bool enabled() const { return mEnabled; } 199 : : 200 : : /** 201 : : * Sets whether the effect is enabled 202 : : * \param enabled set to FALSE to disable the effect 203 : : * \see enabled 204 : : */ 205 : : void setEnabled( bool enabled ); 206 : : 207 : : /** 208 : : * Returns the draw mode for the effect. This property only has an 209 : : * effect if the paint effect is used in a QgsEffectStack. 210 : : * \returns draw mode for effect 211 : : * \see setDrawMode 212 : : */ 213 : 0 : DrawMode drawMode() const { return mDrawMode; } 214 : : 215 : : /** 216 : : * Sets the draw mode for the effect. This property only has an 217 : : * effect if the paint effect is used in a QgsEffectStack. 218 : : * \param drawMode draw mode for effect 219 : : * \see drawMode 220 : : */ 221 : : void setDrawMode( DrawMode drawMode ); 222 : : 223 : : protected: 224 : : 225 : 713 : bool mEnabled = true; 226 : 713 : DrawMode mDrawMode = ModifyAndRender; 227 : 713 : bool requiresQPainterDpiFix = true; 228 : : 229 : : /** 230 : : * Handles drawing of the effect's result on to the specified render context. 231 : : * Derived classes must reimplement this method to apply any transformations to 232 : : * the source QPicture and draw the result using the context's painter. 233 : : * \param context destination render context 234 : : * \see drawSource 235 : : */ 236 : : virtual void draw( QgsRenderContext &context ) = 0; 237 : : 238 : : /** 239 : : * Draws the source QPicture onto the specified painter. Handles scaling of the picture 240 : : * to account for the destination painter's DPI. 241 : : * \param painter destination painter 242 : : * \see source 243 : : * \see sourceAsImage 244 : : */ 245 : : void drawSource( QPainter &painter ); 246 : : 247 : : /** 248 : : * Returns the source QPicture. The draw() member can utilize this when 249 : : * drawing the effect. 250 : : * \returns source QPicture 251 : : * \see drawSource 252 : : * \see sourceAsImage 253 : : */ 254 : 0 : const QPicture *source() const { return mPicture; } 255 : : 256 : : /** 257 : : * Returns the source QPicture rendered to a new QImage. The draw() member can 258 : : * utilize this when drawing the effect. The image will be padded or cropped from the original 259 : : * source QPicture by the results of the boundingRect() method. 260 : : * The result is cached to speed up subsequent calls to sourceAsImage. 261 : : * \returns source QPicture rendered to an image 262 : : * \see drawSource 263 : : * \see source 264 : : * \see imageOffset 265 : : * \see boundingRect 266 : : */ 267 : : QImage *sourceAsImage( QgsRenderContext &context ); 268 : : 269 : : /** 270 : : * Returns the offset which should be used when drawing the source image on to a destination 271 : : * render context. 272 : : * \param context destination render context 273 : : * \returns point offset for image top left corner 274 : : * \see sourceAsImage 275 : : */ 276 : : QPointF imageOffset( const QgsRenderContext &context ) const; 277 : : 278 : : /** 279 : : * Returns the bounding rect required for drawing the effect. This method can be used 280 : : * to expand the bounding rect of a source picture to account for offset or blurring 281 : : * effects. 282 : : * \param rect original source bounding rect 283 : : * \param context destination render context 284 : : * \returns modified bounding rect 285 : : * \see sourceAsImage 286 : : */ 287 : : virtual QRectF boundingRect( const QRectF &rect, const QgsRenderContext &context ) const; 288 : : 289 : : /** 290 : : * Applies a workaround to a QPainter to avoid an issue with incorrect scaling 291 : : * when drawing QPictures. This may need to be called by derived classes prior 292 : : * to rendering results onto a painter. 293 : : * \param painter destination painter 294 : : */ 295 : : void fixQPictureDpi( QPainter *painter ) const; 296 : : 297 : : private: 298 : : 299 : 713 : const QPicture *mPicture = nullptr; 300 : 713 : QImage *mSourceImage = nullptr; 301 : 713 : bool mOwnsImage = false; 302 : : 303 : 713 : QPainter *mPrevPainter = nullptr; 304 : 713 : QPainter *mEffectPainter = nullptr; 305 : 713 : QPicture *mTempPicture = nullptr; 306 : : 307 : : QRectF imageBoundingRect( const QgsRenderContext &context ) const; 308 : : 309 : : friend class QgsEffectStack; 310 : : 311 : : QgsPaintEffect &operator= ( const QgsPaintEffect & ) = delete; 312 : : 313 : : }; 314 : : 315 : : /** 316 : : * \ingroup core 317 : : * \class QgsDrawSourceEffect 318 : : * \brief A paint effect which draws the source picture with minor or no alterations 319 : : * 320 : : * The draw source effect can be used to draw an unaltered copy of the original source 321 : : * picture. Minor changes like lowering the opacity and applying a blend mode are 322 : : * supported, however these changes will force the resultant output to be rasterized. 323 : : * If no alterations are performed then the original picture will be rendered as a vector. 324 : : * 325 : : * \since QGIS 2.9 326 : : */ 327 : : 328 : 172 : class CORE_EXPORT QgsDrawSourceEffect : public QgsPaintEffect SIP_NODEFAULTCTORS 329 : : { 330 : : public: 331 : : 332 : : //! Constructor for QgsDrawSourceEffect 333 : 118 : QgsDrawSourceEffect() = default; 334 : : 335 : : /** 336 : : * Creates a new QgsDrawSource effect from a properties string map. 337 : : * \param map encoded properties string map 338 : : * \returns new QgsDrawSourceEffect 339 : : */ 340 : : static QgsPaintEffect *create( const QVariantMap &map ) SIP_FACTORY; 341 : : 342 : 0 : QString type() const override { return QStringLiteral( "drawSource" ); } 343 : : QgsDrawSourceEffect *clone() const override SIP_FACTORY; 344 : : QVariantMap properties() const override; 345 : : void readProperties( const QVariantMap &props ) override; 346 : : 347 : : /** 348 : : * Sets the \a opacity for the effect. 349 : : * \param opacity double between 0 and 1 inclusive, where 0 is fully transparent 350 : : * and 1 is fully opaque 351 : : * \see opacity() 352 : : */ 353 : : void setOpacity( const double opacity ) { mOpacity = opacity; } 354 : : 355 : : /** 356 : : * Returns the opacity for the effect 357 : : * \returns opacity value between 0 and 1 inclusive, where 0 is fully transparent 358 : : * and 1 is fully opaque 359 : : * \see setOpacity() 360 : : */ 361 : 0 : double opacity() const { return mOpacity; } 362 : : 363 : : /** 364 : : * Sets the blend mode for the effect 365 : : * \param mode blend mode used for drawing the source on to a destination 366 : : * paint device 367 : : * \see blendMode 368 : : */ 369 : : void setBlendMode( const QPainter::CompositionMode mode ) { mBlendMode = mode; } 370 : : 371 : : /** 372 : : * Returns the blend mode for the effect 373 : : * \returns blend mode used for drawing the source on to a destination 374 : : * paint device 375 : : * \see setBlendMode 376 : : */ 377 : 0 : QPainter::CompositionMode blendMode() const { return mBlendMode; } 378 : : 379 : : protected: 380 : : 381 : : void draw( QgsRenderContext &context ) override; 382 : : 383 : : private: 384 : : 385 : 118 : double mOpacity = 1.0; 386 : 118 : QPainter::CompositionMode mBlendMode = QPainter::CompositionMode_SourceOver; 387 : : }; 388 : : 389 : : /** 390 : : * \ingroup core 391 : : * \class QgsEffectPainter 392 : : * \brief A class to manager painter saving and restoring required for effect drawing 393 : : * 394 : : * \since QGIS 3.0 395 : : */ 396 : : class CORE_EXPORT QgsEffectPainter 397 : : { 398 : : public: 399 : : 400 : : /** 401 : : * QgsEffectPainter constructor 402 : : * 403 : : * \param renderContext the QgsRenderContext object 404 : : * \since QGIS 3.0 405 : : */ 406 : : QgsEffectPainter( QgsRenderContext &renderContext ); 407 : : 408 : : /** 409 : : * QgsEffectPainter constructor alternative if no painter translation is needed 410 : : * 411 : : * \param renderContext the QgsRenderContext object 412 : : * \param effect the QgsPaintEffect object 413 : : * \since QGIS 3.0 414 : : */ 415 : : QgsEffectPainter( QgsRenderContext &renderContext, QgsPaintEffect *effect ); 416 : : ~QgsEffectPainter(); 417 : : 418 : : /** 419 : : * Sets the effect to be painted 420 : : * 421 : : * \param effect the QgsPaintEffect object 422 : : */ 423 : : void setEffect( QgsPaintEffect *effect ); 424 : : 425 : : ///@cond PRIVATE 426 : : 427 : : /** 428 : : * Access to the painter object 429 : : * 430 : : * \since QGIS 3.0 431 : : */ 432 : 0 : QPainter *operator->() { return mPainter; } 433 : : ///@endcond 434 : : 435 : : private: 436 : : #ifdef SIP_RUN 437 : : const QgsEffectPainter &operator=( const QgsEffectPainter & ); 438 : : #endif 439 : : 440 : : QgsRenderContext &mRenderContext; 441 : : QPainter *mPainter = nullptr; 442 : : QgsPaintEffect *mEffect = nullptr; 443 : : }; 444 : : 445 : : #endif // QGSPAINTEFFECT_H 446 : :