QGIS API Documentation 3.39.0-Master (d85f3c2a281)
Loading...
Searching...
No Matches
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{
53 if ( &rhs == this )
54 return *this;
55
56 //deep copy
57 clearStack();
58 for ( int i = 0; i < rhs.count(); ++i )
59 {
60 appendEffect( rhs.effect( i )->clone() );
61 }
62 mEnabled = rhs.enabled();
63 return *this;
64}
65
67{
68 std::swap( mEffectList, other.mEffectList );
69 mEnabled = other.enabled();
70 return *this;
71}
72
73QgsPaintEffect *QgsEffectStack::create( const QVariantMap &map )
74{
76 effect->readProperties( map );
77 return effect;
78}
79
81{
82 QPainter *destPainter = context.painter();
83
84 //first, we build up a list of rendered effects
85 //we do this moving backwards through the stack, so that each effect's results
86 //becomes the source of the previous effect
87 QPicture *sourcePic = new QPicture( *source() );
88 QPicture *currentPic = sourcePic;
89 QList< QPicture * > results;
90 for ( int i = mEffectList.count() - 1; i >= 0; --i )
91 {
92 QgsPaintEffect *effect = mEffectList.at( i );
93 if ( !effect->enabled() )
94 {
95 continue;
96 }
97
98 QPicture *pic = nullptr;
99 if ( effect->type() == QLatin1String( "drawSource" ) )
100 {
101 //draw source is always the original source, regardless of previous effect results
102 pic = sourcePic;
103 }
104 else
105 {
106 pic = currentPic;
107 }
108
109 QPicture *resultPic = new QPicture();
110 QPainter p( resultPic );
111 context.setPainter( &p );
112 //effect stack has it's own handling of the QPicture DPI issue, so
113 //we disable QgsPaintEffect's internal workaround
115 effect->render( *pic, context );
117 p.end();
118
119 results << resultPic;
120 if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Render )
121 {
122 currentPic = resultPic;
123 }
124 }
125 delete sourcePic;
126 sourcePic = nullptr;
127
128 context.setPainter( destPainter );
129 //then, we render all the results in the opposite order
130 for ( int i = 0; i < mEffectList.count(); ++i )
131 {
132 if ( !mEffectList[i]->enabled() )
133 {
134 continue;
135 }
136
137 QPicture *pic = results.takeLast();
138 if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Modifier )
139 {
140 QgsPainting::drawPicture( context.painter(), QPointF( 0, 0 ), *pic );
141 }
142 delete pic;
143 }
144}
145
147{
148 return new QgsEffectStack( *this );
149}
150
151bool QgsEffectStack::saveProperties( QDomDocument &doc, QDomElement &element ) const
152{
153 //effect stack needs to save all child effects
154 if ( element.isNull() )
155 {
156 return false;
157 }
158
159 QDomElement effectElement = doc.createElement( QStringLiteral( "effect" ) );
160 effectElement.setAttribute( QStringLiteral( "type" ), type() );
161 effectElement.setAttribute( QStringLiteral( "enabled" ), mEnabled );
162
163 bool ok = true;
164 for ( QgsPaintEffect *effect : mEffectList )
165 {
166 if ( effect )
167 ok = ok && effect->saveProperties( doc, effectElement );
168 }
169
170 element.appendChild( effectElement );
171 return ok;
172}
173
174bool QgsEffectStack::readProperties( const QDomElement &element )
175{
176 if ( element.isNull() )
177 {
178 return false;
179 }
180
181 mEnabled = ( element.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
182
183 clearStack();
184
185 //restore all child effects
186 const QDomNodeList childNodes = element.childNodes();
187 for ( int i = 0; i < childNodes.size(); ++i )
188 {
189 const QDomElement childElement = childNodes.at( i ).toElement();
191 if ( effect )
192 mEffectList << effect;
193 }
194 return true;
195}
196
197QVariantMap QgsEffectStack::properties() const
198{
199 QVariantMap props;
200 return props;
201}
202
203void QgsEffectStack::readProperties( const QVariantMap &props )
204{
205 Q_UNUSED( props )
206}
207
208void QgsEffectStack::clearStack()
209{
210 qDeleteAll( mEffectList );
211 mEffectList.clear();
212}
213
215{
216 mEffectList.append( effect );
217}
218
219bool QgsEffectStack::insertEffect( const int index, QgsPaintEffect *effect )
220{
221 if ( index < 0 || index > mEffectList.count() )
222 return false;
223 if ( !effect )
224 return false;
225
226 mEffectList.insert( index, effect );
227 return true;
228}
229
230bool QgsEffectStack::changeEffect( const int index, QgsPaintEffect *effect )
231{
232 if ( index < 0 || index >= mEffectList.count() )
233 return false;
234 if ( !effect )
235 return false;
236
237 delete mEffectList.at( index );
238 mEffectList[index] = effect;
239 return true;
240}
241
243{
244 if ( index < 0 || index >= mEffectList.count() )
245 return nullptr;
246
247 return mEffectList.takeAt( index );
248}
249
250QList<QgsPaintEffect *> *QgsEffectStack::effectList()
251{
252 return &mEffectList;
253}
254
256{
257 if ( index >= 0 && index < mEffectList.count() )
258 {
259 return mEffectList.at( index );
260 }
261 else
262 {
263 return nullptr;
264 }
265}
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.
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.
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.
@ 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.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.