QGIS API Documentation 3.99.0-Master (b927df884fe)
qgseffectstack.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgseffectstack.cpp
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
18#include "qgseffectstack.h"
20#include "qgsrendercontext.h"
21#include "qgsapplication.h"
22#include "qgspainting.h"
23#include <QPicture>
24
26 : QgsPaintEffect( other )
27{
28 //deep copy
29 for ( int i = 0; i < other.count(); ++i )
30 {
31 appendEffect( other.effect( i )->clone() );
32 }
33}
34
36 : QgsPaintEffect( other )
37{
38 std::swap( mEffectList, other.mEffectList );
39}
40
45
47{
48 clearStack();
49}
50
52{
54 for ( const QgsPaintEffect *effect : mEffectList )
55 {
57 {
59 }
60 }
61 return res;
62}
63
65{
66 if ( &rhs == this )
67 return *this;
68
69 //deep copy
70 clearStack();
71 for ( int i = 0; i < rhs.count(); ++i )
72 {
73 appendEffect( rhs.effect( i )->clone() );
74 }
75 mEnabled = rhs.enabled();
76 return *this;
77}
78
80{
81 std::swap( mEffectList, other.mEffectList );
82 mEnabled = other.enabled();
83 return *this;
84}
85
86QgsPaintEffect *QgsEffectStack::create( const QVariantMap &map )
87{
89 effect->readProperties( map );
90 return effect;
91}
92
94{
95 QPainter *destPainter = context.painter();
96
98 {
99 // can we render this stack if we're forcing vectors?
100 bool requiresRasterization = false;
101 for ( const QgsPaintEffect *effect : std::as_const( mEffectList ) )
102 {
104 {
105 requiresRasterization = true;
106 break;
107 }
108 }
109
110 if ( requiresRasterization )
111 {
112 //just draw unmodified source, we can't render this effect stack when forcing vectors
113 drawSource( *context.painter() );
114 }
115 return;
116 }
117
118 //first, we build up a list of rendered effects
119 //we do this moving backwards through the stack, so that each effect's results
120 //becomes the source of the previous effect
121 const QPicture sourcePic = source();
122 const QPicture *currentPic = &sourcePic;
123 std::vector< QPicture > results;
124 results.reserve( mEffectList.count() );
125 for ( int i = mEffectList.count() - 1; i >= 0; --i )
126 {
127 QgsPaintEffect *effect = mEffectList.at( i );
128 if ( !effect->enabled() )
129 {
130 continue;
131 }
132
133 const QPicture *pic = nullptr;
134 if ( effect->type() == QLatin1String( "drawSource" ) )
135 {
136 //draw source is always the original source, regardless of previous effect results
137 pic = &sourcePic;
138 }
139 else
140 {
141 pic = currentPic;
142 }
143
144 QPicture resultPic;
145 QPainter p( &resultPic );
146 context.setPainter( &p );
147 //effect stack has it's own handling of the QPicture DPI issue, so
148 //we disable QgsPaintEffect's internal workaround
150 effect->render( *pic, context );
152 p.end();
153
154 results.emplace_back( std::move( resultPic ) );
155 if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Render )
156 {
157 currentPic = &results.back();
158 }
159 }
160
161 context.setPainter( destPainter );
162 //then, we render all the results in the opposite order
163 for ( int i = 0; i < mEffectList.count(); ++i )
164 {
165 if ( !mEffectList[i]->enabled() )
166 {
167 continue;
168 }
169
170 if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Modifier )
171 {
172 QgsPainting::drawPicture( context.painter(), QPointF( 0, 0 ), results.back() );
173 }
174 results.pop_back();
175 }
176}
177
179{
180 return new QgsEffectStack( *this );
181}
182
183bool QgsEffectStack::saveProperties( QDomDocument &doc, QDomElement &element ) const
184{
185 //effect stack needs to save all child effects
186 if ( element.isNull() )
187 {
188 return false;
189 }
190
191 QDomElement effectElement = doc.createElement( QStringLiteral( "effect" ) );
192 effectElement.setAttribute( QStringLiteral( "type" ), type() );
193 effectElement.setAttribute( QStringLiteral( "enabled" ), mEnabled );
194
195 bool ok = true;
196 for ( QgsPaintEffect *effect : mEffectList )
197 {
198 if ( effect )
199 ok = ok && effect->saveProperties( doc, effectElement );
200 }
201
202 element.appendChild( effectElement );
203 return ok;
204}
205
206bool QgsEffectStack::readProperties( const QDomElement &element )
207{
208 if ( element.isNull() )
209 {
210 return false;
211 }
212
213 mEnabled = ( element.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
214
215 clearStack();
216
217 //restore all child effects
218 const QDomNodeList childNodes = element.childNodes();
219 for ( int i = 0; i < childNodes.size(); ++i )
220 {
221 const QDomElement childElement = childNodes.at( i ).toElement();
223 if ( effect )
224 mEffectList << effect;
225 }
226 return true;
227}
228
229QVariantMap QgsEffectStack::properties() const
230{
231 QVariantMap props;
232 return props;
233}
234
235void QgsEffectStack::readProperties( const QVariantMap &props )
236{
237 Q_UNUSED( props )
238}
239
240void QgsEffectStack::clearStack()
241{
242 qDeleteAll( mEffectList );
243 mEffectList.clear();
244}
245
247{
248 mEffectList.append( effect );
249}
250
251bool QgsEffectStack::insertEffect( const int index, QgsPaintEffect *effect )
252{
253 if ( index < 0 || index > mEffectList.count() )
254 return false;
255 if ( !effect )
256 return false;
257
258 mEffectList.insert( index, effect );
259 return true;
260}
261
262bool QgsEffectStack::changeEffect( const int index, QgsPaintEffect *effect )
263{
264 if ( index < 0 || index >= mEffectList.count() )
265 return false;
266 if ( !effect )
267 return false;
268
269 delete mEffectList.at( index );
270 mEffectList[index] = effect;
271 return true;
272}
273
275{
276 if ( index < 0 || index >= mEffectList.count() )
277 return nullptr;
278
279 return mEffectList.takeAt( index );
280}
281
282QList<QgsPaintEffect *> *QgsEffectStack::effectList()
283{
284 return &mEffectList;
285}
286
288{
289 if ( index >= 0 && index < mEffectList.count() )
290 {
291 return mEffectList.at( index );
292 }
293 else
294 {
295 return nullptr;
296 }
297}
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
@ RequiresRasterization
The effect requires raster-based rendering.
QFlags< PaintEffectFlag > PaintEffectFlags
Flags which control how paint effects behave.
Definition qgis.h:2765
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application's paint effect registry, used for managing paint effects.
A paint effect which consists of a stack of other chained paint effects.
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
QgsEffectStack()=default
bool saveProperties(QDomDocument &doc, QDomElement &element) const override
Saves the current state of the effect to a DOM element.
void draw(QgsRenderContext &context) override
Handles drawing of the effect's result on to the specified render context.
QgsEffectStack & operator=(const QgsEffectStack &rhs)
QString type() const override
Returns the effect type.
Qgis::PaintEffectFlags flags() const override
Returns flags which specify how the paint effect behaves.
static QgsPaintEffect * create(const QVariantMap &map)
Creates a new QgsEffectStack effect.
bool readProperties(const QDomElement &element) override
Restores the effect to the state described by a DOM element.
~QgsEffectStack() override
QList< QgsPaintEffect * > * effectList()
Returns a pointer to the list of effects currently contained by the stack.
QVariantMap properties() const override
Unused for QgsEffectStack, will always return an empty string map.
int count() const
Returns count of effects contained by the stack.
QgsEffectStack * clone() const override
Duplicates an effect by creating a deep copy of the effect.
bool insertEffect(int index, QgsPaintEffect *effect)
Inserts an effect at a specified index within the stack.
QgsPaintEffect * takeEffect(int index)
Removes an effect from the stack and returns a pointer to it.
bool changeEffect(int index, QgsPaintEffect *effect)
Replaces the effect at a specified position within the stack.
QgsPaintEffect * effect(int index) const
Returns a pointer to the effect at a specified index within the stack.
QgsPaintEffect * createEffect(const QString &name, const QVariantMap &properties=QVariantMap()) const
Creates a new paint effect given the effect name and properties map.
Base class for visual effects which can be applied to QPicture drawings.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
void drawSource(QPainter &painter)
Draws the source QPicture onto the specified painter.
virtual void readProperties(const QVariantMap &props)=0
Reads a string map of an effect's properties and restores the effect to the state described by the pr...
const QPicture & source() const
Returns the source QPicture.
bool enabled() const
Returns whether the effect is enabled.
virtual Qgis::PaintEffectFlags flags() const
Returns flags which specify how the paint effect behaves.
virtual void render(const QPicture &picture, QgsRenderContext &context)
Renders a picture using the effect.
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
@ Render
The result of the effect is rendered on the destination, but does not affect subsequent effects in th...
@ Modifier
The result of the effect is not rendered, but is passed on to following effects in the stack.
virtual QString type() const =0
Returns the effect type.
static void drawPicture(QPainter *painter, const QPointF &point, const QPicture &picture)
Draws a picture onto a painter, correctly applying workarounds to avoid issues with incorrect scaling...
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
Qgis::RasterizedRenderingPolicy rasterizedRenderingPolicy() const
Returns the policy controlling when rasterisation of content during renders is permitted.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.