QGIS API Documentation 3.41.0-Master (1deb1daf037)
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 const QPicture sourcePic = source();
88 const QPicture *currentPic = &sourcePic;
89 std::vector< QPicture > results;
90 results.reserve( mEffectList.count() );
91 for ( int i = mEffectList.count() - 1; i >= 0; --i )
92 {
93 QgsPaintEffect *effect = mEffectList.at( i );
94 if ( !effect->enabled() )
95 {
96 continue;
97 }
98
99 const QPicture *pic = nullptr;
100 if ( effect->type() == QLatin1String( "drawSource" ) )
101 {
102 //draw source is always the original source, regardless of previous effect results
103 pic = &sourcePic;
104 }
105 else
106 {
107 pic = currentPic;
108 }
109
110 QPicture resultPic;
111 QPainter p( &resultPic );
112 context.setPainter( &p );
113 //effect stack has it's own handling of the QPicture DPI issue, so
114 //we disable QgsPaintEffect's internal workaround
116 effect->render( *pic, context );
118 p.end();
119
120 results.emplace_back( std::move( resultPic ) );
121 if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Render )
122 {
123 currentPic = &results.back();
124 }
125 }
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 if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Modifier )
137 {
138 QgsPainting::drawPicture( context.painter(), QPointF( 0, 0 ), results.back() );
139 }
140 results.pop_back();
141 }
142}
143
145{
146 return new QgsEffectStack( *this );
147}
148
149bool QgsEffectStack::saveProperties( QDomDocument &doc, QDomElement &element ) const
150{
151 //effect stack needs to save all child effects
152 if ( element.isNull() )
153 {
154 return false;
155 }
156
157 QDomElement effectElement = doc.createElement( QStringLiteral( "effect" ) );
158 effectElement.setAttribute( QStringLiteral( "type" ), type() );
159 effectElement.setAttribute( QStringLiteral( "enabled" ), mEnabled );
160
161 bool ok = true;
162 for ( QgsPaintEffect *effect : mEffectList )
163 {
164 if ( effect )
165 ok = ok && effect->saveProperties( doc, effectElement );
166 }
167
168 element.appendChild( effectElement );
169 return ok;
170}
171
172bool QgsEffectStack::readProperties( const QDomElement &element )
173{
174 if ( element.isNull() )
175 {
176 return false;
177 }
178
179 mEnabled = ( element.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
180
181 clearStack();
182
183 //restore all child effects
184 const QDomNodeList childNodes = element.childNodes();
185 for ( int i = 0; i < childNodes.size(); ++i )
186 {
187 const QDomElement childElement = childNodes.at( i ).toElement();
189 if ( effect )
190 mEffectList << effect;
191 }
192 return true;
193}
194
195QVariantMap QgsEffectStack::properties() const
196{
197 QVariantMap props;
198 return props;
199}
200
201void QgsEffectStack::readProperties( const QVariantMap &props )
202{
203 Q_UNUSED( props )
204}
205
206void QgsEffectStack::clearStack()
207{
208 qDeleteAll( mEffectList );
209 mEffectList.clear();
210}
211
213{
214 mEffectList.append( effect );
215}
216
217bool QgsEffectStack::insertEffect( const int index, QgsPaintEffect *effect )
218{
219 if ( index < 0 || index > mEffectList.count() )
220 return false;
221 if ( !effect )
222 return false;
223
224 mEffectList.insert( index, effect );
225 return true;
226}
227
228bool QgsEffectStack::changeEffect( const int index, QgsPaintEffect *effect )
229{
230 if ( index < 0 || index >= mEffectList.count() )
231 return false;
232 if ( !effect )
233 return false;
234
235 delete mEffectList.at( index );
236 mEffectList[index] = effect;
237 return true;
238}
239
241{
242 if ( index < 0 || index >= mEffectList.count() )
243 return nullptr;
244
245 return mEffectList.takeAt( index );
246}
247
248QList<QgsPaintEffect *> *QgsEffectStack::effectList()
249{
250 return &mEffectList;
251}
252
254{
255 if ( index >= 0 && index < mEffectList.count() )
256 {
257 return mEffectList.at( index );
258 }
259 else
260 {
261 return nullptr;
262 }
263}
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...
const QPicture & source() const
Returns the source QPicture.
bool enabled() const
Returns whether the effect is enabled.
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.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.