QGIS API Documentation  2.18.3-Las Palmas (77b8c3d)
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
const T & at(int i) const
bool enabled() const
Returns whether the effect is enabled.
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
void append(const T &value)
int count() const
Returns count of effects contained by the stack.
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)
void setPainter(QPainter *p)
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.
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 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()
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.
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.
void drawPicture(const QPointF &point, const QPicture &picture)
const QPicture * source() const
Returns the source QPicture.
int size() const
QDomElement createElement(const QString &tagName)
virtual QgsStringMap properties() const override
Unused for QgsEffectStack, will always return an empty string map.
QgsPaintEffect * effect(int index) const
Returns a pointer to the effect at a specified index 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.
QDomNode at(int index) const
QgsPaintEffect * takeEffect(const int index)
Removes an effect from the stack and returns a pointer to it.