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