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