QGIS API Documentation 3.27.0-Master (f261cc1f8b)
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 <QPicture>
23
25 : QgsPaintEffect( other )
26{
27 //deep copy
28 for ( int i = 0; i < other.count(); ++i )
29 {
30 appendEffect( other.effect( i )->clone() );
31 }
32}
33
35 : QgsPaintEffect( other )
36{
37 std::swap( mEffectList, other.mEffectList );
38}
39
41{
43}
44
46{
47 clearStack();
48}
49
51{
52 if ( &rhs == this )
53 return *this;
54
55 //deep copy
56 clearStack();
57 for ( int i = 0; i < rhs.count(); ++i )
58 {
59 appendEffect( rhs.effect( i )->clone() );
60 }
61 mEnabled = rhs.enabled();
62 return *this;
63}
64
66{
67 std::swap( mEffectList, other.mEffectList );
68 mEnabled = other.enabled();
69 return *this;
70}
71
72QgsPaintEffect *QgsEffectStack::create( const QVariantMap &map )
73{
75 effect->readProperties( map );
76 return effect;
77}
78
80{
81 QPainter *destPainter = context.painter();
82
83 //first, we build up a list of rendered effects
84 //we do this moving backwards through the stack, so that each effect's results
85 //becomes the source of the previous effect
86 QPicture *sourcePic = new QPicture( *source() );
87 QPicture *currentPic = sourcePic;
88 QList< QPicture * > results;
89 for ( int i = mEffectList.count() - 1; i >= 0; --i )
90 {
91 QgsPaintEffect *effect = mEffectList.at( i );
92 if ( !effect->enabled() )
93 {
94 continue;
95 }
96
97 QPicture *pic = nullptr;
98 if ( effect->type() == QLatin1String( "drawSource" ) )
99 {
100 //draw source is always the original source, regardless of previous effect results
101 pic = sourcePic;
102 }
103 else
104 {
105 pic = currentPic;
106 }
107
108 QPicture *resultPic = new QPicture();
109 QPainter p( resultPic );
110 context.setPainter( &p );
111 //effect stack has it's own handling of the QPicture DPI issue, so
112 //we disable QgsPaintEffect's internal workaround
114 effect->render( *pic, context );
116 p.end();
117
118 results << resultPic;
119 if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Render )
120 {
121 currentPic = resultPic;
122 }
123 }
124 delete sourcePic;
125 sourcePic = nullptr;
126
127 context.setPainter( destPainter );
128 //then, we render all the results in the opposite order
129 for ( int i = 0; i < mEffectList.count(); ++i )
130 {
131 if ( !mEffectList[i]->enabled() )
132 {
133 continue;
134 }
135
136 QPicture *pic = results.takeLast();
137 if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Modifier )
138 {
139 const QgsScopedQPainterState painterState( context.painter() );
140 fixQPictureDpi( context.painter() );
141 context.painter()->drawPicture( 0, 0, *pic );
142 }
143 delete pic;
144 }
145}
146
148{
149 return new QgsEffectStack( *this );
150}
151
152bool QgsEffectStack::saveProperties( QDomDocument &doc, QDomElement &element ) const
153{
154 //effect stack needs to save all child effects
155 if ( element.isNull() )
156 {
157 return false;
158 }
159
160 QDomElement effectElement = doc.createElement( QStringLiteral( "effect" ) );
161 effectElement.setAttribute( QStringLiteral( "type" ), type() );
162 effectElement.setAttribute( QStringLiteral( "enabled" ), mEnabled );
163
164 bool ok = true;
165 for ( QgsPaintEffect *effect : mEffectList )
166 {
167 if ( effect )
168 ok = ok && effect->saveProperties( doc, effectElement );
169 }
170
171 element.appendChild( effectElement );
172 return ok;
173}
174
175bool QgsEffectStack::readProperties( const QDomElement &element )
176{
177 if ( element.isNull() )
178 {
179 return false;
180 }
181
182 mEnabled = ( element.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
183
184 clearStack();
185
186 //restore all child effects
187 const QDomNodeList childNodes = element.childNodes();
188 for ( int i = 0; i < childNodes.size(); ++i )
189 {
190 const QDomElement childElement = childNodes.at( i ).toElement();
192 if ( effect )
193 mEffectList << effect;
194 }
195 return true;
196}
197
198QVariantMap QgsEffectStack::properties() const
199{
200 QVariantMap props;
201 return props;
202}
203
204void QgsEffectStack::readProperties( const QVariantMap &props )
205{
206 Q_UNUSED( props )
207}
208
209void QgsEffectStack::clearStack()
210{
211 qDeleteAll( mEffectList );
212 mEffectList.clear();
213}
214
216{
217 mEffectList.append( effect );
218}
219
220bool QgsEffectStack::insertEffect( const int index, QgsPaintEffect *effect )
221{
222 if ( index < 0 || index > mEffectList.count() )
223 return false;
224 if ( !effect )
225 return false;
226
227 mEffectList.insert( index, effect );
228 return true;
229}
230
231bool QgsEffectStack::changeEffect( const int index, QgsPaintEffect *effect )
232{
233 if ( index < 0 || index >= mEffectList.count() )
234 return false;
235 if ( !effect )
236 return false;
237
238 delete mEffectList.at( index );
239 mEffectList[index] = effect;
240 return true;
241}
242
244{
245 if ( index < 0 || index >= mEffectList.count() )
246 return nullptr;
247
248 return mEffectList.takeAt( index );
249}
250
251QList<QgsPaintEffect *> *QgsEffectStack::effectList()
252{
253 return &mEffectList;
254}
255
257{
258 if ( index >= 0 && index < mEffectList.count() )
259 {
260 return mEffectList.at( index );
261 }
262 else
263 {
264 return nullptr;
265 }
266}
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
Constructor for empty QgsEffectStack.
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.
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.
bool requiresQPainterDpiFix
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
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...
virtual void render(QPicture &picture, QgsRenderContext &context)
Renders a picture using the effect.
const QPicture * source() const
Returns the source QPicture.
bool enabled() const
Returns whether the effect is enabled.
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
void fixQPictureDpi(QPainter *painter) const
Applies a workaround to a QPainter to avoid an issue with incorrect scaling when drawing QPictures.
@ 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.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
Scoped object for saving and restoring a QPainter object's state.