QGIS API Documentation  3.2.0-Bonn (bc43194)
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"
19 #include "qgspainteffectregistry.h"
20 #include "qgsrendercontext.h"
21 #include <QPicture>
22 
24  : QgsPaintEffect( other )
25 {
26  //deep copy
27  for ( int i = 0; i < other.count(); ++i )
28  {
29  appendEffect( other.effect( i )->clone() );
30  }
31 }
32 
34 {
35  appendEffect( effect.clone() );
36 }
37 
39 {
40  clearStack();
41 }
42 
44 {
45  if ( &rhs == this )
46  return *this;
47 
48  //deep copy
49  clearStack();
50  for ( int i = 0; i < rhs.count(); ++i )
51  {
52  appendEffect( rhs.effect( i )->clone() );
53  }
54  mEnabled = rhs.enabled();
55  return *this;
56 }
57 
59 {
61  effect->readProperties( map );
62  return effect;
63 }
64 
66 {
67  QPainter *destPainter = context.painter();
68 
69  //first, we build up a list of rendered effects
70  //we do this moving backwards through the stack, so that each effect's results
71  //becomes the source of the previous effect
72  QPicture *sourcePic = new QPicture( *source() );
73  QPicture *currentPic = sourcePic;
74  QList< QPicture * > results;
75  for ( int i = mEffectList.count() - 1; i >= 0; --i )
76  {
77  QgsPaintEffect *effect = mEffectList.at( i );
78  if ( !effect->enabled() )
79  {
80  continue;
81  }
82 
83  QPicture *pic = nullptr;
84  if ( effect->type() == QLatin1String( "drawSource" ) )
85  {
86  //draw source is always the original source, regardless of previous effect results
87  pic = sourcePic;
88  }
89  else
90  {
91  pic = currentPic;
92  }
93 
94  QPicture *resultPic = new QPicture();
95  QPainter p( resultPic );
96  context.setPainter( &p );
97  //effect stack has it's own handling of the QPicture DPI issue, so
98  //we disable QgsPaintEffect's internal workaround
99  effect->requiresQPainterDpiFix = false;
100  effect->render( *pic, context );
101  effect->requiresQPainterDpiFix = true;
102  p.end();
103 
104  results << resultPic;
105  if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Render )
106  {
107  currentPic = resultPic;
108  }
109  }
110  delete sourcePic;
111  sourcePic = nullptr;
112 
113  context.setPainter( destPainter );
114  //then, we render all the results in the opposite order
115  for ( int i = 0; i < mEffectList.count(); ++i )
116  {
117  if ( !mEffectList[i]->enabled() )
118  {
119  continue;
120  }
121 
122  QPicture *pic = results.takeLast();
123  if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Modifier )
124  {
125  context.painter()->save();
126  fixQPictureDpi( context.painter() );
127  context.painter()->drawPicture( 0, 0, *pic );
128  context.painter()->restore();
129 
130  }
131  delete pic;
132  }
133 }
134 
136 {
137  return new QgsEffectStack( *this );
138 }
139 
140 bool QgsEffectStack::saveProperties( QDomDocument &doc, QDomElement &element ) const
141 {
142  //effect stack needs to save all child effects
143  if ( element.isNull() )
144  {
145  return false;
146  }
147 
148  QDomElement effectElement = doc.createElement( QStringLiteral( "effect" ) );
149  effectElement.setAttribute( QStringLiteral( "type" ), type() );
150  effectElement.setAttribute( QStringLiteral( "enabled" ), mEnabled );
151 
152  bool ok = true;
153  for ( QgsPaintEffect *effect : mEffectList )
154  {
155  if ( effect )
156  ok = ok && effect->saveProperties( doc, effectElement );
157  }
158 
159  element.appendChild( effectElement );
160  return ok;
161 }
162 
163 bool QgsEffectStack::readProperties( const QDomElement &element )
164 {
165  if ( element.isNull() )
166  {
167  return false;
168  }
169 
170  mEnabled = ( element.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
171 
172  clearStack();
173 
174  //restore all child effects
175  QDomNodeList childNodes = element.childNodes();
176  for ( int i = 0; i < childNodes.size(); ++i )
177  {
178  QDomElement childElement = childNodes.at( i ).toElement();
180  if ( effect )
181  mEffectList << effect;
182  }
183  return true;
184 }
185 
187 {
188  QgsStringMap props;
189  return props;
190 }
191 
193 {
194  Q_UNUSED( props );
195 }
196 
197 void QgsEffectStack::clearStack()
198 {
199  qDeleteAll( mEffectList );
200  mEffectList.clear();
201 }
202 
204 {
205  mEffectList.append( effect );
206 }
207 
209 {
210  if ( index < 0 || index > mEffectList.count() )
211  return false;
212  if ( !effect )
213  return false;
214 
215  mEffectList.insert( index, effect );
216  return true;
217 }
218 
220 {
221  if ( index < 0 || index >= mEffectList.count() )
222  return false;
223  if ( !effect )
224  return false;
225 
226  delete mEffectList.at( index );
227  mEffectList[index] = effect;
228  return true;
229 }
230 
232 {
233  if ( index < 0 || index >= mEffectList.count() )
234  return nullptr;
235 
236  return mEffectList.takeAt( index );
237 }
238 
239 QList<QgsPaintEffect *> *QgsEffectStack::effectList()
240 {
241  return &mEffectList;
242 }
243 
245 {
246  if ( index >= 0 && index < mEffectList.count() )
247  {
248  return mEffectList.at( index );
249  }
250  else
251  {
252  return nullptr;
253  }
254 }
bool insertEffect(int index, QgsPaintEffect *effect)
Inserts an effect at a specified index within the stack.
The result of the effect is rendered on the destination, but does not affect subsequent effects in th...
void fixQPictureDpi(QPainter *painter) const
Applies a workaround to a QPainter to avoid an issue with incorrect scaling when drawing QPictures...
Base class for visual effects which can be applied to QPicture drawings.
~QgsEffectStack() override
void draw(QgsRenderContext &context) override
Handles drawing of the effect&#39;s result on to the specified render context.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:501
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application&#39;s paint effect registry, used for managing paint effects. ...
bool saveProperties(QDomDocument &doc, QDomElement &element) const override
Saves the current state of the effect to a DOM element.
bool readProperties(const QDomElement &element) override
Restores the effect to the state described by a DOM element.
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
static QgsPaintEffect * create(const QgsStringMap &map)
Creates a new QgsEffectStack effect.
int count() const
Returns count of effects contained by the stack.
virtual QString type() const =0
Returns the effect type.
QgsPaintEffect * effect(int index) const
Returns a pointer to the effect at a specified index within the stack.
QString type() const override
Returns the effect type.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
A paint effect which consists of a stack of other chained paint effects.
QgsEffectStack * clone() const override
Duplicates an effect by creating a deep copy of the effect.
bool enabled() const
Returns whether the effect is enabled.
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
The result of the effect is not rendered, but is passed on to following effects in the stack...
bool requiresQPainterDpiFix
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
QList< QgsPaintEffect *> * effectList()
Returns a pointer to the list of effects currently contained by the stack.
QgsEffectStack & operator=(const QgsEffectStack &rhs)
virtual void render(QPicture &picture, QgsRenderContext &context)
Renders a picture using the effect.
QgsPaintEffect * takeEffect(int index)
Removes an effect from the stack and returns a pointer to it.
const QPicture * source() const
Returns the source QPicture.
QgsPaintEffect * createEffect(const QString &name, const QgsStringMap &properties=QgsStringMap()) const
Creates a new paint effect given the effect name and properties map.
QgsStringMap properties() const override
Unused for QgsEffectStack, will always return an empty string map.
QgsEffectStack()=default
Constructor for empty QgsEffectStack.
bool changeEffect(int index, QgsPaintEffect *effect)
Replaces the effect at a specified position within the stack.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.