QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 <QPicture>
21 
23  : QgsPaintEffect()
24 {
25 
26 }
27 
29  : QgsPaintEffect( other )
30 {
31  //deep copy
32  for ( int i = 0; i < other.count(); ++i )
33  {
34  appendEffect( other.effect( i )->clone() );
35  }
36 }
37 
39  : QgsPaintEffect()
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 {
67  effect->readProperties( map );
68  return effect;
69 }
70 
72 {
73  QPainter* destPainter = context.painter();
74 
75  //first, we build up a list of rendered effects
76  //we do this moving backwards through the stack, so that each effect's results
77  //becomes the source of the previous effect
78  QPicture* sourcePic = new QPicture( *source() );
79  QPicture* currentPic = sourcePic;
80  QList< QPicture* > results;
81  for ( int i = mEffectList.count() - 1; i >= 0; --i )
82  {
83  QgsPaintEffect* effect = mEffectList.at( i );
84  if ( !effect->enabled() )
85  {
86  continue;
87  }
88 
89  QPicture* pic;
90  if ( effect->type() == "drawSource" )
91  {
92  //draw source is always the original source, regardless of previous effect results
93  pic = sourcePic;
94  }
95  else
96  {
97  pic = currentPic;
98  }
99 
100  QPicture *resultPic = new QPicture();
101  QPainter p( resultPic );
102  context.setPainter( &p );
103  //effect stack has it's own handling of the QPicture DPI issue, so
104  //we disable QgsPaintEffect's internal workaround
105  effect->requiresQPainterDpiFix = false;
106  effect->render( *pic, context );
107  effect->requiresQPainterDpiFix = true;
108  p.end();
109 
110  results << resultPic;
111  if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Render )
112  {
113  currentPic = resultPic;
114  }
115  }
116  delete sourcePic;
117  sourcePic = nullptr;
118 
119  context.setPainter( destPainter );
120  //then, we render all the results in the opposite order
121  for ( int i = 0; i < mEffectList.count(); ++i )
122  {
123  if ( !mEffectList[i]->enabled() )
124  {
125  continue;
126  }
127 
128  QPicture* pic = results.takeLast();
129  if ( mEffectList.at( i )->drawMode() != QgsPaintEffect::Modifier )
130  {
131  context.painter()->save();
132  fixQPictureDpi( context.painter() );
133  context.painter()->drawPicture( 0, 0, *pic );
134  context.painter()->restore();
135 
136  }
137  delete pic;
138  }
139 }
140 
142 {
143  return new QgsEffectStack( *this );
144 }
145 
147 {
148  //effect stack needs to save all child effects
149  if ( element.isNull() )
150  {
151  return false;
152  }
153 
154  QDomElement effectElement = doc.createElement( "effect" );
155  effectElement.setAttribute( QString( "type" ), type() );
156  effectElement.setAttribute( QString( "enabled" ), mEnabled );
157 
158  bool ok = true;
159  Q_FOREACH ( QgsPaintEffect* effect, mEffectList )
160  {
161  if ( effect )
162  ok = ok && effect->saveProperties( doc, effectElement );
163  }
164 
165  element.appendChild( effectElement );
166  return ok;
167 }
168 
170 {
171  if ( element.isNull() )
172  {
173  return false;
174  }
175 
176  mEnabled = ( element.attribute( "enabled", "0" ) != "0" );
177 
178  clearStack();
179 
180  //restore all child effects
181  QDomNodeList childNodes = element.childNodes();
182  for ( int i = 0; i < childNodes.size(); ++i )
183  {
184  QDomElement childElement = childNodes.at( i ).toElement();
186  if ( effect )
187  mEffectList << effect;
188  }
189  return true;
190 }
191 
193 {
194  QgsStringMap props;
195  return props;
196 }
197 
199 {
200  Q_UNUSED( props );
201 }
202 
203 void QgsEffectStack::clearStack()
204 {
205  qDeleteAll( mEffectList );
206  mEffectList.clear();
207 }
208 
210 {
211  mEffectList.append( effect );
212 }
213 
215 {
216  if ( index < 0 || index > mEffectList.count() )
217  return false;
218  if ( !effect )
219  return false;
220 
221  mEffectList.insert( index, effect );
222  return true;
223 }
224 
226 {
227  if ( index < 0 || index >= mEffectList.count() )
228  return false;
229  if ( !effect )
230  return false;
231 
232  delete mEffectList.at( index );
233  mEffectList[index] = effect;
234  return true;
235 }
236 
238 {
239  if ( index < 0 || index >= mEffectList.count() )
240  return nullptr;
241 
242  return mEffectList.takeAt( index );
243 }
244 
246 {
247  return &mEffectList;
248 }
249 
251 {
252  if ( index >= 0 && index < mEffectList.count() )
253  {
254  return mEffectList.at( index );
255  }
256  else
257  {
258  return nullptr;
259  }
260 }
void clear()
static unsigned index
bool end()
QDomNode appendChild(const QDomNode &newChild)
QString attribute(const QString &name, const QString &defValue) const
void fixQPictureDpi(QPainter *painter) const
Applies a workaround to a QPainter to avoid an issue with incorrect scaling when drawing QPictures...
const T & at(int i) const
Base class for visual effects which can be applied to QPicture drawings.
virtual QString type() const override
Returns the effect type.
void save()
virtual void draw(QgsRenderContext &context) override
Handles drawing of the effect&#39;s result on to the specified render context.
T takeAt(int i)
QDomNodeList childNodes() const
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const override
Saves the current state of the effect to a DOM element.
virtual 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.
QDomElement toElement() const
int count(const T &value) const
int count() const
Returns count of effects contained by the stack.
void append(const T &value)
static QgsPaintEffectRegistry * instance()
Returns a reference to the singleton instance of the paint effect registry.
virtual QString type() const =0
Returns the effect type.
void setAttribute(const QString &name, const QString &value)
QgsPaintEffect * effect(int index) const
Returns a pointer to the effect at a specified index within the stack.
void setPainter(QPainter *p)
A paint effect which consists of a stack of other chained paint effects.
virtual QgsEffectStack * clone() const override
Duplicates an effect by creating a deep copy of the effect.
bool changeEffect(const int index, QgsPaintEffect *effect)
Replaces the effect at a specified position within the stack.
bool enabled() const
Returns whether the effect is enabled.
bool insertEffect(const int index, QgsPaintEffect *effect)
Inserts an effect at a specified index within the stack.
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
bool requiresQPainterDpiFix
bool isNull() const
void restore()
Contains information about the context of a rendering operation.
T takeLast()
QPainter * painter()
void insert(int i, const T &value)
virtual ~QgsEffectStack()
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.
const QPicture * source() const
Returns the source QPicture.
void drawPicture(const QPointF &point, const QPicture &picture)
int size() const
QDomElement createElement(const QString &tagName)
QgsPaintEffect * createEffect(const QString &name, const QgsStringMap &properties=QgsStringMap()) const
Creates a new paint effect given the effect name and properties map.
virtual QgsStringMap properties() const override
Unused for QgsEffectStack, will always return an empty string map.
QDomNode at(int index) const
QgsPaintEffect * takeEffect(const int index)
Removes an effect from the stack and returns a pointer to it.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.