QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
18#include "qgstextrenderer_p.h"
19#include "qgsvectorlayer.h"
20#include "qgspallabeling.h"
21#include "qgssymbollayerutils.h"
22#include "qgspainting.h"
25#include "qgsapplication.h"
26#include "qgsunittypes.h"
27#include "qgscolorutils.h"
28
30{
31 d = new QgsTextBufferSettingsPrivate();
32}
33
35 : d( other.d )
36{
37}
38
40{
41 d = other.d;
42 return *this;
43}
44
46{
47
48}
49
51{
52 if ( d->enabled != other.enabled()
53 || d->size != other.size()
54 || d->sizeUnit != other.sizeUnit()
55 || d->sizeMapUnitScale != other.sizeMapUnitScale()
56 || d->color != other.color()
57 || d->opacity != other.opacity()
58 || d->fillBufferInterior != other.fillBufferInterior()
59 || d->joinStyle != other.joinStyle()
60 || d->blendMode != other.blendMode() )
61 return false;
62
63 if ( static_cast< bool >( d->paintEffect ) != static_cast< bool >( other.paintEffect() )
64 || ( d->paintEffect && d->paintEffect->properties() != other.paintEffect()->properties() ) )
65 return false;
66
67 return true;
68}
69
71{
72 return !( *this == other );
73}
74
76{
77 return d->enabled;
78}
79
81{
82 d->enabled = enabled;
83}
84
86{
87 return d->size;
88}
89
91{
92 d->size = size;
93}
94
96{
97 return d->sizeUnit;
98}
99
101{
102 d->sizeUnit = unit;
103}
104
106{
107 return d->sizeMapUnitScale;
108}
109
111{
112 d->sizeMapUnitScale = scale;
113}
114
116{
117 return d->color;
118}
119
120void QgsTextBufferSettings::setColor( const QColor &color )
121{
122 d->color = color;
123}
124
126{
127 return d->fillBufferInterior;
128}
129
131{
132 d->fillBufferInterior = fill;
133}
134
136{
137 return d->opacity;
138}
139
141{
142 d->opacity = opacity;
143}
144
145Qt::PenJoinStyle QgsTextBufferSettings::joinStyle() const
146{
147 return d->joinStyle;
148}
149
150void QgsTextBufferSettings::setJoinStyle( Qt::PenJoinStyle style )
151{
152 d->joinStyle = style;
153}
154
155QPainter::CompositionMode QgsTextBufferSettings::blendMode() const
156{
157 return d->blendMode;
158}
159
160void QgsTextBufferSettings::setBlendMode( QPainter::CompositionMode mode )
161{
162 d->blendMode = mode;
163}
164
166{
167 return d->paintEffect.get();
168}
169
171{
172 d->paintEffect.reset( effect );
173}
174
176{
178 {
179 context.expressionContext().setOriginalValueVariable( d->enabled );
180 d->enabled = properties.valueAsBool( QgsPalLayerSettings::Property::BufferDraw, context.expressionContext(), d->enabled );
181 }
182
184 {
185 context.expressionContext().setOriginalValueVariable( d->size );
186 d->size = properties.valueAsDouble( QgsPalLayerSettings::Property::BufferSize, context.expressionContext(), d->size );
187 }
188
189 QVariant exprVal = properties.value( QgsPalLayerSettings::Property::BufferUnit, context.expressionContext() );
190 if ( !QgsVariantUtils::isNull( exprVal ) )
191 {
192 const QString units = exprVal.toString();
193 if ( !units.isEmpty() )
194 {
195 bool ok;
196 const Qgis::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
197 if ( ok )
198 d->sizeUnit = res;
199 }
200 }
201
203 {
204 context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
205 const QVariant val = properties.value( QgsPalLayerSettings::Property::BufferOpacity, context.expressionContext(), d->opacity * 100 );
206 if ( !QgsVariantUtils::isNull( val ) )
207 {
208 d->opacity = val.toDouble() / 100.0;
209 }
210 }
211
213 {
215 d->color = properties.valueAsColor( QgsPalLayerSettings::Property::BufferColor, context.expressionContext(), d->color );
216 }
217
219 {
221 const QString blendstr = exprVal.toString().trimmed();
222 if ( !blendstr.isEmpty() )
223 d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
224 }
225
227 {
229 const QString joinstr = exprVal.toString().trimmed();
230 if ( !joinstr.isEmpty() )
231 {
232 d->joinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( joinstr );
233 }
234 }
235}
236
238{
239 return QSet< QString >(); // nothing for now
240}
241
243{
244 // text buffer
245 const double bufSize = layer->customProperty( QStringLiteral( "labeling/bufferSize" ), QVariant( 0.0 ) ).toDouble();
246
247 // fix for buffer being keyed off of just its size in the past (<2.0)
248 const QVariant drawBuffer = layer->customProperty( QStringLiteral( "labeling/bufferDraw" ), QVariant() );
249 if ( drawBuffer.isValid() )
250 {
251 d->enabled = drawBuffer.toBool();
252 d->size = bufSize;
253 }
254 else if ( bufSize != 0.0 )
255 {
256 d->enabled = true;
257 d->size = bufSize;
258 }
259 else
260 {
261 // keep bufferSize at new 1.0 default
262 d->enabled = false;
263 }
264
265 if ( layer->customProperty( QStringLiteral( "labeling/bufferSizeUnits" ) ).toString().isEmpty() )
266 {
267 const bool bufferSizeInMapUnits = layer->customProperty( QStringLiteral( "labeling/bufferSizeInMapUnits" ) ).toBool();
268 d->sizeUnit = bufferSizeInMapUnits ? Qgis::RenderUnit::MapUnits : Qgis::RenderUnit::Millimeters;
269 }
270 else
271 {
272 d->sizeUnit = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/bufferSizeUnits" ) ).toString() );
273 }
274
275 if ( layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitScale" ) ).toString().isEmpty() )
276 {
277 //fallback to older property
278 const double oldMin = layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitMinScale" ), 0.0 ).toDouble();
279 d->sizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
280 const double oldMax = layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitMaxScale" ), 0.0 ).toDouble();
281 d->sizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
282 }
283 else
284 {
285 d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitScale" ) ).toString() );
286 }
287 d->color = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/bufferColor" ), Qt::white, false );
288 if ( layer->customProperty( QStringLiteral( "labeling/bufferOpacity" ) ).toString().isEmpty() )
289 {
290 d->opacity = ( 1 - layer->customProperty( QStringLiteral( "labeling/bufferTransp" ) ).toInt() / 100.0 ); //0 -100
291 }
292 else
293 {
294 d->opacity = ( layer->customProperty( QStringLiteral( "labeling/bufferOpacity" ) ).toDouble() );
295 }
296 d->blendMode = QgsPainting::getCompositionMode(
297 static_cast< Qgis::BlendMode >( layer->customProperty( QStringLiteral( "labeling/bufferBlendMode" ), QVariant( static_cast< int >( Qgis::BlendMode::Normal ) ) ).toUInt() ) );
298 d->joinStyle = static_cast< Qt::PenJoinStyle >( layer->customProperty( QStringLiteral( "labeling/bufferJoinStyle" ), QVariant( Qt::RoundJoin ) ).toUInt() );
299
300 d->fillBufferInterior = !layer->customProperty( QStringLiteral( "labeling/bufferNoFill" ), QVariant( false ) ).toBool();
301
302 if ( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).isValid() )
303 {
304 QDomDocument doc( QStringLiteral( "effect" ) );
305 doc.setContent( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).toString() );
306 const QDomElement effectElem = doc.firstChildElement( QStringLiteral( "effect" ) ).firstChildElement( QStringLiteral( "effect" ) );
307 setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
308 }
309 else
310 setPaintEffect( nullptr );
311}
312
313void QgsTextBufferSettings::readXml( const QDomElement &elem )
314{
315 const QDomElement textBufferElem = elem.firstChildElement( QStringLiteral( "text-buffer" ) );
316 const double bufSize = textBufferElem.attribute( QStringLiteral( "bufferSize" ), QStringLiteral( "0" ) ).toDouble();
317
318 // fix for buffer being keyed off of just its size in the past (<2.0)
319 const QVariant drawBuffer = textBufferElem.attribute( QStringLiteral( "bufferDraw" ) );
320 if ( drawBuffer.isValid() )
321 {
322 d->enabled = drawBuffer.toBool();
323 d->size = bufSize;
324 }
325 else if ( bufSize != 0.0 )
326 {
327 d->enabled = true;
328 d->size = bufSize;
329 }
330 else
331 {
332 // keep bufferSize at new 1.0 default
333 d->enabled = false;
334 }
335
336 if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferSizeUnits" ) ) )
337 {
338 const bool bufferSizeInMapUnits = textBufferElem.attribute( QStringLiteral( "bufferSizeInMapUnits" ) ).toInt();
339 d->sizeUnit = bufferSizeInMapUnits ? Qgis::RenderUnit::MapUnits : Qgis::RenderUnit::Millimeters;
340 }
341 else
342 {
343 d->sizeUnit = QgsUnitTypes::decodeRenderUnit( textBufferElem.attribute( QStringLiteral( "bufferSizeUnits" ) ) );
344 }
345
346 if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferSizeMapUnitScale" ) ) )
347 {
348 //fallback to older property
349 const double oldMin = textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
350 d->sizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
351 const double oldMax = textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
352 d->sizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
353 }
354 else
355 {
356 d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitScale" ) ) );
357 }
358 d->color = QgsColorUtils::colorFromString( textBufferElem.attribute( QStringLiteral( "bufferColor" ), QgsColorUtils::colorToString( Qt::white ) ) );
359
360 if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferOpacity" ) ) )
361 {
362 d->opacity = ( 1 - textBufferElem.attribute( QStringLiteral( "bufferTransp" ) ).toInt() / 100.0 ); //0 -100
363 }
364 else
365 {
366 d->opacity = ( textBufferElem.attribute( QStringLiteral( "bufferOpacity" ) ).toDouble() );
367 }
368
369 d->blendMode = QgsPainting::getCompositionMode(
370 static_cast< Qgis::BlendMode >( textBufferElem.attribute( QStringLiteral( "bufferBlendMode" ), QString::number( static_cast< int >( Qgis::BlendMode::Normal ) ) ).toUInt() ) );
371 d->joinStyle = static_cast< Qt::PenJoinStyle >( textBufferElem.attribute( QStringLiteral( "bufferJoinStyle" ), QString::number( Qt::RoundJoin ) ).toUInt() );
372 d->fillBufferInterior = !textBufferElem.attribute( QStringLiteral( "bufferNoFill" ), QStringLiteral( "0" ) ).toInt();
373 const QDomElement effectElem = textBufferElem.firstChildElement( QStringLiteral( "effect" ) );
374 if ( !effectElem.isNull() )
376 else
377 setPaintEffect( nullptr );
378}
379
380QDomElement QgsTextBufferSettings::writeXml( QDomDocument &doc ) const
381{
382 // text buffer
383 QDomElement textBufferElem = doc.createElement( QStringLiteral( "text-buffer" ) );
384 textBufferElem.setAttribute( QStringLiteral( "bufferDraw" ), d->enabled );
385 textBufferElem.setAttribute( QStringLiteral( "bufferSize" ), d->size );
386 textBufferElem.setAttribute( QStringLiteral( "bufferSizeUnits" ), QgsUnitTypes::encodeUnit( d->sizeUnit ) );
387 textBufferElem.setAttribute( QStringLiteral( "bufferSizeMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->sizeMapUnitScale ) );
388 textBufferElem.setAttribute( QStringLiteral( "bufferColor" ), QgsColorUtils::colorToString( d->color ) );
389 textBufferElem.setAttribute( QStringLiteral( "bufferNoFill" ), !d->fillBufferInterior );
390 textBufferElem.setAttribute( QStringLiteral( "bufferOpacity" ), d->opacity );
391 textBufferElem.setAttribute( QStringLiteral( "bufferJoinStyle" ), static_cast< unsigned int >( d->joinStyle ) );
392 textBufferElem.setAttribute( QStringLiteral( "bufferBlendMode" ), static_cast< int >( QgsPainting::getBlendModeEnum( d->blendMode ) ) );
393 if ( d->paintEffect && !QgsPaintEffectRegistry::isDefaultStack( d->paintEffect.get() ) )
394 d->paintEffect->saveProperties( doc, textBufferElem );
395 return textBufferElem;
396}
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition: qgis.h:4041
RenderUnit
Rendering size units.
Definition: qgis.h:4255
@ Millimeters
Millimeters.
@ MapUnits
Map units.
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.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
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 Qgis::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a Qgis::BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:81
static QPainter::CompositionMode getCompositionMode(Qgis::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a Qgis::BlendMode.
Definition: qgspainting.cpp:21
@ 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 final
Returns the calculated value of the property with the specified key from within the collection.
bool isActive(int key) const final
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 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.
Qgis::RenderUnit sizeUnit() const
Returns the units for the buffer size.
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.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
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.
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 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 Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.