QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgstextbuffersettings.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstextbuffersettings.cpp
3  -----------------
4  begin : May 2020
5  copyright : (C) Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7 
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgstextbuffersettings.h"
18 #include "qgstextrenderer_p.h"
19 #include "qgsvectorlayer.h"
20 #include "qgspallabeling.h"
21 #include "qgssymbollayerutils.h"
22 #include "qgspainting.h"
23 #include "qgspainteffectregistry.h"
24 #include "qgstextrendererutils.h"
25 
27 {
28  d = new QgsTextBufferSettingsPrivate();
29 }
30 
32  : d( other.d )
33 {
34 }
35 
37 {
38  d = other.d;
39  return *this;
40 }
41 
43 {
44 
45 }
46 
48 {
49  if ( d->enabled != other.enabled()
50  || d->size != other.size()
51  || d->sizeUnit != other.sizeUnit()
52  || d->sizeMapUnitScale != other.sizeMapUnitScale()
53  || d->color != other.color()
54  || d->opacity != other.opacity()
55  || d->fillBufferInterior != other.fillBufferInterior()
56  || d->joinStyle != other.joinStyle()
57  || d->blendMode != other.blendMode() )
58  return false;
59 
60  if ( static_cast< bool >( d->paintEffect ) != static_cast< bool >( other.paintEffect() )
61  || ( d->paintEffect && d->paintEffect->properties() != other.paintEffect()->properties() ) )
62  return false;
63 
64  return true;
65 }
66 
68 {
69  return !( *this == other );
70 }
71 
73 {
74  return d->enabled;
75 }
76 
78 {
79  d->enabled = enabled;
80 }
81 
83 {
84  return d->size;
85 }
86 
87 void QgsTextBufferSettings::setSize( double size )
88 {
89  d->size = size;
90 }
91 
93 {
94  return d->sizeUnit;
95 }
96 
98 {
99  d->sizeUnit = unit;
100 }
101 
103 {
104  return d->sizeMapUnitScale;
105 }
106 
108 {
109  d->sizeMapUnitScale = scale;
110 }
111 
113 {
114  return d->color;
115 }
116 
117 void QgsTextBufferSettings::setColor( const QColor &color )
118 {
119  d->color = color;
120 }
121 
123 {
124  return d->fillBufferInterior;
125 }
126 
128 {
129  d->fillBufferInterior = fill;
130 }
131 
133 {
134  return d->opacity;
135 }
136 
137 void QgsTextBufferSettings::setOpacity( double opacity )
138 {
139  d->opacity = opacity;
140 }
141 
142 Qt::PenJoinStyle QgsTextBufferSettings::joinStyle() const
143 {
144  return d->joinStyle;
145 }
146 
147 void QgsTextBufferSettings::setJoinStyle( Qt::PenJoinStyle style )
148 {
149  d->joinStyle = style;
150 }
151 
152 QPainter::CompositionMode QgsTextBufferSettings::blendMode() const
153 {
154  return d->blendMode;
155 }
156 
157 void QgsTextBufferSettings::setBlendMode( QPainter::CompositionMode mode )
158 {
159  d->blendMode = mode;
160 }
161 
163 {
164  return d->paintEffect.get();
165 }
166 
168 {
169  d->paintEffect.reset( effect );
170 }
171 
173 {
174  if ( properties.isActive( QgsPalLayerSettings::BufferDraw ) )
175  {
176  context.expressionContext().setOriginalValueVariable( d->enabled );
177  d->enabled = properties.valueAsBool( QgsPalLayerSettings::BufferDraw, context.expressionContext(), d->enabled );
178  }
179 
180  if ( properties.isActive( QgsPalLayerSettings::BufferSize ) )
181  {
182  context.expressionContext().setOriginalValueVariable( d->size );
183  d->size = properties.valueAsDouble( QgsPalLayerSettings::BufferSize, context.expressionContext(), d->size );
184  }
185 
186  QVariant exprVal = properties.value( QgsPalLayerSettings::BufferUnit, context.expressionContext() );
187  if ( !exprVal.isNull() )
188  {
189  const QString units = exprVal.toString();
190  if ( !units.isEmpty() )
191  {
192  bool ok;
194  if ( ok )
195  d->sizeUnit = res;
196  }
197  }
198 
199  if ( properties.isActive( QgsPalLayerSettings::BufferOpacity ) )
200  {
201  context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
202  const QVariant val = properties.value( QgsPalLayerSettings::BufferOpacity, context.expressionContext(), d->opacity * 100 );
203  if ( !val.isNull() )
204  {
205  d->opacity = val.toDouble() / 100.0;
206  }
207  }
208 
209  if ( properties.isActive( QgsPalLayerSettings::BufferColor ) )
210  {
212  d->color = properties.valueAsColor( QgsPalLayerSettings::BufferColor, context.expressionContext(), d->color );
213  }
214 
216  {
217  exprVal = properties.value( QgsPalLayerSettings::BufferBlendMode, context.expressionContext() );
218  const QString blendstr = exprVal.toString().trimmed();
219  if ( !blendstr.isEmpty() )
220  d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
221  }
222 
224  {
225  exprVal = properties.value( QgsPalLayerSettings::BufferJoinStyle, context.expressionContext() );
226  const QString joinstr = exprVal.toString().trimmed();
227  if ( !joinstr.isEmpty() )
228  {
229  d->joinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( joinstr );
230  }
231  }
232 }
233 
235 {
236  return QSet< QString >(); // nothing for now
237 }
238 
240 {
241  // text buffer
242  const double bufSize = layer->customProperty( QStringLiteral( "labeling/bufferSize" ), QVariant( 0.0 ) ).toDouble();
243 
244  // fix for buffer being keyed off of just its size in the past (<2.0)
245  const QVariant drawBuffer = layer->customProperty( QStringLiteral( "labeling/bufferDraw" ), QVariant() );
246  if ( drawBuffer.isValid() )
247  {
248  d->enabled = drawBuffer.toBool();
249  d->size = bufSize;
250  }
251  else if ( bufSize != 0.0 )
252  {
253  d->enabled = true;
254  d->size = bufSize;
255  }
256  else
257  {
258  // keep bufferSize at new 1.0 default
259  d->enabled = false;
260  }
261 
262  if ( layer->customProperty( QStringLiteral( "labeling/bufferSizeUnits" ) ).toString().isEmpty() )
263  {
264  const bool bufferSizeInMapUnits = layer->customProperty( QStringLiteral( "labeling/bufferSizeInMapUnits" ) ).toBool();
265  d->sizeUnit = bufferSizeInMapUnits ? QgsUnitTypes::RenderMapUnits : QgsUnitTypes::RenderMillimeters;
266  }
267  else
268  {
269  d->sizeUnit = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/bufferSizeUnits" ) ).toString() );
270  }
271 
272  if ( layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitScale" ) ).toString().isEmpty() )
273  {
274  //fallback to older property
275  const double oldMin = layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitMinScale" ), 0.0 ).toDouble();
276  d->sizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
277  const double oldMax = layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitMaxScale" ), 0.0 ).toDouble();
278  d->sizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
279  }
280  else
281  {
282  d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitScale" ) ).toString() );
283  }
284  d->color = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/bufferColor" ), Qt::white, false );
285  if ( layer->customProperty( QStringLiteral( "labeling/bufferOpacity" ) ).toString().isEmpty() )
286  {
287  d->opacity = ( 1 - layer->customProperty( QStringLiteral( "labeling/bufferTransp" ) ).toInt() / 100.0 ); //0 -100
288  }
289  else
290  {
291  d->opacity = ( layer->customProperty( QStringLiteral( "labeling/bufferOpacity" ) ).toDouble() );
292  }
293  d->blendMode = QgsPainting::getCompositionMode(
294  static_cast< QgsPainting::BlendMode >( layer->customProperty( QStringLiteral( "labeling/bufferBlendMode" ), QVariant( QgsPainting::BlendNormal ) ).toUInt() ) );
295  d->joinStyle = static_cast< Qt::PenJoinStyle >( layer->customProperty( QStringLiteral( "labeling/bufferJoinStyle" ), QVariant( Qt::RoundJoin ) ).toUInt() );
296 
297  d->fillBufferInterior = !layer->customProperty( QStringLiteral( "labeling/bufferNoFill" ), QVariant( false ) ).toBool();
298 
299  if ( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).isValid() )
300  {
301  QDomDocument doc( QStringLiteral( "effect" ) );
302  doc.setContent( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).toString() );
303  const QDomElement effectElem = doc.firstChildElement( QStringLiteral( "effect" ) ).firstChildElement( QStringLiteral( "effect" ) );
304  setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
305  }
306  else
307  setPaintEffect( nullptr );
308 }
309 
310 void QgsTextBufferSettings::readXml( const QDomElement &elem )
311 {
312  const QDomElement textBufferElem = elem.firstChildElement( QStringLiteral( "text-buffer" ) );
313  const double bufSize = textBufferElem.attribute( QStringLiteral( "bufferSize" ), QStringLiteral( "0" ) ).toDouble();
314 
315  // fix for buffer being keyed off of just its size in the past (<2.0)
316  const QVariant drawBuffer = textBufferElem.attribute( QStringLiteral( "bufferDraw" ) );
317  if ( drawBuffer.isValid() )
318  {
319  d->enabled = drawBuffer.toBool();
320  d->size = bufSize;
321  }
322  else if ( bufSize != 0.0 )
323  {
324  d->enabled = true;
325  d->size = bufSize;
326  }
327  else
328  {
329  // keep bufferSize at new 1.0 default
330  d->enabled = false;
331  }
332 
333  if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferSizeUnits" ) ) )
334  {
335  const bool bufferSizeInMapUnits = textBufferElem.attribute( QStringLiteral( "bufferSizeInMapUnits" ) ).toInt();
336  d->sizeUnit = bufferSizeInMapUnits ? QgsUnitTypes::RenderMapUnits : QgsUnitTypes::RenderMillimeters;
337  }
338  else
339  {
340  d->sizeUnit = QgsUnitTypes::decodeRenderUnit( textBufferElem.attribute( QStringLiteral( "bufferSizeUnits" ) ) );
341  }
342 
343  if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferSizeMapUnitScale" ) ) )
344  {
345  //fallback to older property
346  const double oldMin = textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
347  d->sizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
348  const double oldMax = textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
349  d->sizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
350  }
351  else
352  {
353  d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitScale" ) ) );
354  }
355  d->color = QgsSymbolLayerUtils::decodeColor( textBufferElem.attribute( QStringLiteral( "bufferColor" ), QgsSymbolLayerUtils::encodeColor( Qt::white ) ) );
356 
357  if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferOpacity" ) ) )
358  {
359  d->opacity = ( 1 - textBufferElem.attribute( QStringLiteral( "bufferTransp" ) ).toInt() / 100.0 ); //0 -100
360  }
361  else
362  {
363  d->opacity = ( textBufferElem.attribute( QStringLiteral( "bufferOpacity" ) ).toDouble() );
364  }
365 
366  d->blendMode = QgsPainting::getCompositionMode(
367  static_cast< QgsPainting::BlendMode >( textBufferElem.attribute( QStringLiteral( "bufferBlendMode" ), QString::number( QgsPainting::BlendNormal ) ).toUInt() ) );
368  d->joinStyle = static_cast< Qt::PenJoinStyle >( textBufferElem.attribute( QStringLiteral( "bufferJoinStyle" ), QString::number( Qt::RoundJoin ) ).toUInt() );
369  d->fillBufferInterior = !textBufferElem.attribute( QStringLiteral( "bufferNoFill" ), QStringLiteral( "0" ) ).toInt();
370  const QDomElement effectElem = textBufferElem.firstChildElement( QStringLiteral( "effect" ) );
371  if ( !effectElem.isNull() )
373  else
374  setPaintEffect( nullptr );
375 }
376 
377 QDomElement QgsTextBufferSettings::writeXml( QDomDocument &doc ) const
378 {
379  // text buffer
380  QDomElement textBufferElem = doc.createElement( QStringLiteral( "text-buffer" ) );
381  textBufferElem.setAttribute( QStringLiteral( "bufferDraw" ), d->enabled );
382  textBufferElem.setAttribute( QStringLiteral( "bufferSize" ), d->size );
383  textBufferElem.setAttribute( QStringLiteral( "bufferSizeUnits" ), QgsUnitTypes::encodeUnit( d->sizeUnit ) );
384  textBufferElem.setAttribute( QStringLiteral( "bufferSizeMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->sizeMapUnitScale ) );
385  textBufferElem.setAttribute( QStringLiteral( "bufferColor" ), QgsSymbolLayerUtils::encodeColor( d->color ) );
386  textBufferElem.setAttribute( QStringLiteral( "bufferNoFill" ), !d->fillBufferInterior );
387  textBufferElem.setAttribute( QStringLiteral( "bufferOpacity" ), d->opacity );
388  textBufferElem.setAttribute( QStringLiteral( "bufferJoinStyle" ), static_cast< unsigned int >( d->joinStyle ) );
389  textBufferElem.setAttribute( QStringLiteral( "bufferBlendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) );
390  if ( d->paintEffect && !QgsPaintEffectRegistry::isDefaultStack( d->paintEffect.get() ) )
391  d->paintEffect->saveProperties( doc, textBufferElem );
392  return textBufferElem;
393 }
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color.
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application's paint effect registry, used for managing paint effects.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
Struct for storing maximum and minimum scales for measurements in map units.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
QgsPaintEffect * createEffect(const QString &name, const QVariantMap &properties=QVariantMap()) const
Creates a new paint effect given the effect name and properties map.
Base class for visual effects which can be applied to QPicture drawings.
virtual QVariantMap properties() const =0
Returns the properties describing the paint effect encoded in a string format.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:37
@ BufferOpacity
Buffer opacity.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Contains information about the context of a rendering operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QColor decodeColor(const QString &str)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static QPainter::CompositionMode decodeBlendMode(const QString &s)
static QString encodeColor(const QColor &color)
Container for settings relating to a text buffer.
QgsTextBufferSettings & operator=(const QgsTextBufferSettings &other)
Copy constructor.
void setFillBufferInterior(bool fill)
Sets whether the interior of the buffer will be filled in.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the buffer.
void readFromLayer(QgsVectorLayer *layer)
Reads settings from a layer's custom properties (for QGIS 2.x projects).
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
Qt::PenJoinStyle joinStyle() const
Returns the buffer join style.
double size() const
Returns the size of the buffer.
void setColor(const QColor &color)
Sets the color for the buffer.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the buffer size.
void setOpacity(double opacity)
Sets the buffer opacity.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
bool enabled() const
Returns whether the buffer is enabled.
double opacity() const
Returns the buffer opacity.
bool operator!=(const QgsTextBufferSettings &other) const
QDomElement writeXml(QDomDocument &doc) const
Write settings into a DOM element.
bool fillBufferInterior() const
Returns whether the interior of the buffer will be filled in.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the buffer.
const QgsPaintEffect * paintEffect() const
Returns the current paint effect for the buffer.
QColor color() const
Returns the color of the buffer.
bool operator==(const QgsTextBufferSettings &other) const
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the buffer.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
void updateDataDefinedProperties(QgsRenderContext &context, const QgsPropertyCollection &properties)
Updates the format by evaluating current values of data defined properties.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the buffer.
void setSize(double size)
Sets the size of the buffer.
void readXml(const QDomElement &elem)
Read settings from a DOM element.
static QColor readColor(QgsVectorLayer *layer, const QString &property, const QColor &defaultColor=Qt::black, bool withAlpha=true)
Converts an encoded color value from a layer property.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:168
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
Represents a vector layer which manages a vector based data sets.