QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgstextbackgroundsettings.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstextbackgroundsettings.cpp
3  -----------------
4  begin : May 2020
5  copyright : (C) Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgstextrenderer_p.h"
18 #include "qgsvectorlayer.h"
19 #include "qgspallabeling.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgspainting.h"
22 #include "qgstextrendererutils.h"
23 #include "qgspainteffectregistry.h"
24 
26 {
27  d = new QgsTextBackgroundSettingsPrivate();
28 }
29 
31  : d( other.d )
32 {
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->type != other.type()
51  || d->svgFile != other.svgFile()
52  || d->sizeType != other.sizeType()
53  || d->size != other.size()
54  || d->sizeUnits != other.sizeUnit()
55  || d->sizeMapUnitScale != other.sizeMapUnitScale()
56  || d->rotationType != other.rotationType()
57  || d->rotation != other.rotation()
58  || d->offset != other.offset()
59  || d->offsetUnits != other.offsetUnit()
60  || d->offsetMapUnitScale != other.offsetMapUnitScale()
61  || d->radii != other.radii()
62  || d->radiiUnits != other.radiiUnit()
63  || d->radiiMapUnitScale != other.radiiMapUnitScale()
64  || d->blendMode != other.blendMode()
65  || d->fillColor != other.fillColor()
66  || d->strokeColor != other.strokeColor()
67  || d->opacity != other.opacity()
68  || d->strokeWidth != other.strokeWidth()
69  || d->strokeWidthUnits != other.strokeWidthUnit()
70  || d->strokeWidthMapUnitScale != other.strokeWidthMapUnitScale()
71  || d->joinStyle != other.joinStyle() )
72  return false;
73 
74  if ( static_cast< bool >( d->paintEffect ) != static_cast< bool >( other.paintEffect() )
75  || ( d->paintEffect && d->paintEffect->properties() != other.paintEffect()->properties() ) )
76  return false;
77 
78  if ( static_cast< bool >( d->markerSymbol ) != static_cast< bool >( other.markerSymbol() )
79  || ( d->markerSymbol && QgsSymbolLayerUtils::symbolProperties( d->markerSymbol.get() ) != QgsSymbolLayerUtils::symbolProperties( other.markerSymbol() ) ) )
80  return false;
81 
82  return true;
83 }
84 
86 {
87  return !( *this == other );
88 }
89 
91 {
92  return d->enabled;
93 }
94 
96 {
97  d->enabled = enabled;
98 }
99 
101 {
102  return d->type;
103 }
104 
106 {
107  d->type = type;
108 }
109 
111 {
112  return d->svgFile;
113 }
114 
115 void QgsTextBackgroundSettings::setSvgFile( const QString &file )
116 {
117  d->svgFile = file;
118 }
119 
121 {
122  return d->markerSymbol.get();
123 }
124 
126 {
127  d->markerSymbol.reset( symbol );
128 }
129 
131 {
132  return d->sizeType;
133 }
134 
136 {
137  d->sizeType = type;
138 }
139 
141 {
142  return d->size;
143 }
144 
146 {
147  d->size = size;
148 }
149 
151 {
152  return d->sizeUnits;
153 }
154 
156 {
157  d->sizeUnits = unit;
158 }
159 
161 {
162  return d->sizeMapUnitScale;
163 }
164 
166 {
167  d->sizeMapUnitScale = scale;
168 }
169 
171 {
172  return d->rotationType;
173 }
174 
176 {
177  d->rotationType = type;
178 }
179 
181 {
182  return d->rotation;
183 }
184 
186 {
187  d->rotation = rotation;
188 }
189 
191 {
192  return d->offset;
193 }
194 
196 {
197  d->offset = offset;
198 }
199 
201 {
202  return d->offsetUnits;
203 }
204 
206 {
207  d->offsetUnits = units;
208 }
209 
211 {
212  return d->offsetMapUnitScale;
213 }
214 
216 {
217  d->offsetMapUnitScale = scale;
218 }
219 
221 {
222  return d->radii;
223 }
224 
226 {
227  d->radii = radii;
228 }
229 
231 {
232  return d->radiiUnits;
233 }
234 
236 {
237  d->radiiUnits = units;
238 }
239 
241 {
242  return d->radiiMapUnitScale;
243 }
244 
246 {
247  d->radiiMapUnitScale = scale;
248 }
249 
251 {
252  return d->opacity;
253 }
254 
256 {
257  d->opacity = opacity;
258 }
259 
260 QPainter::CompositionMode QgsTextBackgroundSettings::blendMode() const
261 {
262  return d->blendMode;
263 }
264 
265 void QgsTextBackgroundSettings::setBlendMode( QPainter::CompositionMode mode )
266 {
267  d->blendMode = mode;
268 }
269 
271 {
272  return d->fillColor;
273 }
274 
275 void QgsTextBackgroundSettings::setFillColor( const QColor &color )
276 {
277  d->fillColor = color;
278 }
279 
281 {
282  return d->strokeColor;
283 }
284 
285 void QgsTextBackgroundSettings::setStrokeColor( const QColor &color )
286 {
287  d->strokeColor = color;
288 }
289 
291 {
292  return d->strokeWidth;
293 }
294 
296 {
297  d->strokeWidth = width;
298 }
299 
301 {
302  return d->strokeWidthUnits;
303 }
304 
306 {
307  d->strokeWidthUnits = units;
308 }
309 
311 {
312  return d->strokeWidthMapUnitScale;
313 }
314 
316 {
317  d->strokeWidthMapUnitScale = scale;
318 }
319 
320 Qt::PenJoinStyle QgsTextBackgroundSettings::joinStyle() const
321 {
322  return d->joinStyle;
323 }
324 
325 void QgsTextBackgroundSettings::setJoinStyle( Qt::PenJoinStyle style )
326 {
327  d->joinStyle = style;
328 }
329 
331 {
332  return d->paintEffect.get();
333 }
334 
336 {
337  d->paintEffect.reset( effect );
338 }
339 
341 {
342  d->enabled = layer->customProperty( QStringLiteral( "labeling/shapeDraw" ), QVariant( false ) ).toBool();
343  d->type = static_cast< ShapeType >( layer->customProperty( QStringLiteral( "labeling/shapeType" ), QVariant( ShapeRectangle ) ).toUInt() );
344  d->svgFile = layer->customProperty( QStringLiteral( "labeling/shapeSVGFile" ), QVariant( "" ) ).toString();
345  d->sizeType = static_cast< SizeType >( layer->customProperty( QStringLiteral( "labeling/shapeSizeType" ), QVariant( SizeBuffer ) ).toUInt() );
346  d->size = QSizeF( layer->customProperty( QStringLiteral( "labeling/shapeSizeX" ), QVariant( 0.0 ) ).toDouble(),
347  layer->customProperty( QStringLiteral( "labeling/shapeSizeY" ), QVariant( 0.0 ) ).toDouble() );
348 
349  if ( layer->customProperty( QStringLiteral( "labeling/shapeSizeUnit" ) ).toString().isEmpty() )
350  {
351  d->sizeUnits = QgsTextRendererUtils::convertFromOldLabelUnit( layer->customProperty( QStringLiteral( "labeling/shapeSizeUnits" ), 0 ).toUInt() );
352  }
353  else
354  {
355  d->sizeUnits = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/shapeSizeUnit" ) ).toString() );
356  }
357 
358  if ( layer->customProperty( QStringLiteral( "labeling/shapeSizeMapUnitScale" ) ).toString().isEmpty() )
359  {
360  //fallback to older property
361  double oldMin = layer->customProperty( QStringLiteral( "labeling/shapeSizeMapUnitMinScale" ), 0.0 ).toDouble();
362  d->sizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
363  double oldMax = layer->customProperty( QStringLiteral( "labeling/shapeSizeMapUnitMaxScale" ), 0.0 ).toDouble();
364  d->sizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
365  }
366  else
367  {
368  d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/shapeSizeMapUnitScale" ) ).toString() );
369  }
370  d->rotationType = static_cast< RotationType >( layer->customProperty( QStringLiteral( "labeling/shapeRotationType" ), QVariant( RotationSync ) ).toUInt() );
371  d->rotation = layer->customProperty( QStringLiteral( "labeling/shapeRotation" ), QVariant( 0.0 ) ).toDouble();
372  d->offset = QPointF( layer->customProperty( QStringLiteral( "labeling/shapeOffsetX" ), QVariant( 0.0 ) ).toDouble(),
373  layer->customProperty( QStringLiteral( "labeling/shapeOffsetY" ), QVariant( 0.0 ) ).toDouble() );
374 
375  if ( layer->customProperty( QStringLiteral( "labeling/shapeOffsetUnit" ) ).toString().isEmpty() )
376  {
377  d->offsetUnits = QgsTextRendererUtils::convertFromOldLabelUnit( layer->customProperty( QStringLiteral( "labeling/shapeOffsetUnits" ), 0 ).toUInt() );
378  }
379  else
380  {
381  d->offsetUnits = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/shapeOffsetUnit" ) ).toString() );
382  }
383 
384  if ( layer->customProperty( QStringLiteral( "labeling/shapeOffsetMapUnitScale" ) ).toString().isEmpty() )
385  {
386  //fallback to older property
387  double oldMin = layer->customProperty( QStringLiteral( "labeling/shapeOffsetMapUnitMinScale" ), 0.0 ).toDouble();
388  d->offsetMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
389  double oldMax = layer->customProperty( QStringLiteral( "labeling/shapeOffsetMapUnitMaxScale" ), 0.0 ).toDouble();
390  d->offsetMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
391  }
392  else
393  {
394  d->offsetMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/shapeOffsetMapUnitScale" ) ).toString() );
395  }
396  d->radii = QSizeF( layer->customProperty( QStringLiteral( "labeling/shapeRadiiX" ), QVariant( 0.0 ) ).toDouble(),
397  layer->customProperty( QStringLiteral( "labeling/shapeRadiiY" ), QVariant( 0.0 ) ).toDouble() );
398 
399 
400  if ( layer->customProperty( QStringLiteral( "labeling/shapeRadiiUnit" ) ).toString().isEmpty() )
401  {
402  d->radiiUnits = QgsTextRendererUtils::convertFromOldLabelUnit( layer->customProperty( QStringLiteral( "labeling/shapeRadiiUnits" ), 0 ).toUInt() );
403  }
404  else
405  {
406  d->radiiUnits = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/shapeRadiiUnit" ) ).toString() );
407  }
408 
409  if ( layer->customProperty( QStringLiteral( "labeling/shapeRadiiMapUnitScale" ) ).toString().isEmpty() )
410  {
411  //fallback to older property
412  double oldMin = layer->customProperty( QStringLiteral( "labeling/shapeRadiiMapUnitMinScale" ), 0.0 ).toDouble();
413  d->radiiMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
414  double oldMax = layer->customProperty( QStringLiteral( "labeling/shapeRadiiMapUnitMaxScale" ), 0.0 ).toDouble();
415  d->radiiMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
416  }
417  else
418  {
419  d->radiiMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/shapeRadiiMapUnitScale" ) ).toString() );
420  }
421  d->fillColor = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/shapeFillColor" ), Qt::white, true );
422  d->strokeColor = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/shapeBorderColor" ), Qt::darkGray, true );
423  d->strokeWidth = layer->customProperty( QStringLiteral( "labeling/shapeBorderWidth" ), QVariant( .0 ) ).toDouble();
424  if ( layer->customProperty( QStringLiteral( "labeling/shapeBorderWidthUnit" ) ).toString().isEmpty() )
425  {
426  d->strokeWidthUnits = QgsTextRendererUtils::convertFromOldLabelUnit( layer->customProperty( QStringLiteral( "labeling/shapeBorderWidthUnits" ), 0 ).toUInt() );
427  }
428  else
429  {
430  d->strokeWidthUnits = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/shapeBorderWidthUnit" ) ).toString() );
431  }
432  if ( layer->customProperty( QStringLiteral( "labeling/shapeBorderWidthMapUnitScale" ) ).toString().isEmpty() )
433  {
434  //fallback to older property
435  double oldMin = layer->customProperty( QStringLiteral( "labeling/shapeBorderWidthMapUnitMinScale" ), 0.0 ).toDouble();
436  d->strokeWidthMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
437  double oldMax = layer->customProperty( QStringLiteral( "labeling/shapeBorderWidthMapUnitMaxScale" ), 0.0 ).toDouble();
438  d->strokeWidthMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
439  }
440  else
441  {
442  d->strokeWidthMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/shapeBorderWidthMapUnitScale" ) ).toString() );
443  }
444  d->joinStyle = static_cast< Qt::PenJoinStyle >( layer->customProperty( QStringLiteral( "labeling/shapeJoinStyle" ), QVariant( Qt::BevelJoin ) ).toUInt() );
445 
446  if ( layer->customProperty( QStringLiteral( "labeling/shapeOpacity" ) ).toString().isEmpty() )
447  {
448  d->opacity = ( 1 - layer->customProperty( QStringLiteral( "labeling/shapeTransparency" ) ).toInt() / 100.0 ); //0 -100
449  }
450  else
451  {
452  d->opacity = ( layer->customProperty( QStringLiteral( "labeling/shapeOpacity" ) ).toDouble() );
453  }
454  d->blendMode = QgsPainting::getCompositionMode(
455  static_cast< QgsPainting::BlendMode >( layer->customProperty( QStringLiteral( "labeling/shapeBlendMode" ), QVariant( QgsPainting::BlendNormal ) ).toUInt() ) );
456 
457  if ( layer->customProperty( QStringLiteral( "labeling/shapeEffect" ) ).isValid() )
458  {
459  QDomDocument doc( QStringLiteral( "effect" ) );
460  doc.setContent( layer->customProperty( QStringLiteral( "labeling/shapeEffect" ) ).toString() );
461  QDomElement effectElem = doc.firstChildElement( QStringLiteral( "effect" ) ).firstChildElement( QStringLiteral( "effect" ) );
462  setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
463  }
464  else
465  setPaintEffect( nullptr );
466 }
467 
468 void QgsTextBackgroundSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
469 {
470  QDomElement backgroundElem = elem.firstChildElement( QStringLiteral( "background" ) );
471  d->enabled = backgroundElem.attribute( QStringLiteral( "shapeDraw" ), QStringLiteral( "0" ) ).toInt();
472  d->type = static_cast< ShapeType >( backgroundElem.attribute( QStringLiteral( "shapeType" ), QString::number( ShapeRectangle ) ).toUInt() );
473  d->svgFile = QgsSymbolLayerUtils::svgSymbolNameToPath( backgroundElem.attribute( QStringLiteral( "shapeSVGFile" ) ), context.pathResolver() );
474  d->sizeType = static_cast< SizeType >( backgroundElem.attribute( QStringLiteral( "shapeSizeType" ), QString::number( SizeBuffer ) ).toUInt() );
475  d->size = QSizeF( backgroundElem.attribute( QStringLiteral( "shapeSizeX" ), QStringLiteral( "0" ) ).toDouble(),
476  backgroundElem.attribute( QStringLiteral( "shapeSizeY" ), QStringLiteral( "0" ) ).toDouble() );
477 
478  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeSizeUnit" ) ) )
479  {
480  d->sizeUnits = QgsTextRendererUtils::convertFromOldLabelUnit( backgroundElem.attribute( QStringLiteral( "shapeSizeUnits" ) ).toUInt() );
481  }
482  else
483  {
484  d->sizeUnits = QgsUnitTypes::decodeRenderUnit( backgroundElem.attribute( QStringLiteral( "shapeSizeUnit" ) ) );
485  }
486 
487  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeSizeMapUnitScale" ) ) )
488  {
489  //fallback to older property
490  double oldMin = backgroundElem.attribute( QStringLiteral( "shapeSizeMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
491  d->sizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
492  double oldMax = backgroundElem.attribute( QStringLiteral( "shapeSizeMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
493  d->sizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
494  }
495  else
496  {
497  d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( backgroundElem.attribute( QStringLiteral( "shapeSizeMapUnitScale" ) ) );
498  }
499  d->rotationType = static_cast< RotationType >( backgroundElem.attribute( QStringLiteral( "shapeRotationType" ), QString::number( RotationSync ) ).toUInt() );
500  d->rotation = backgroundElem.attribute( QStringLiteral( "shapeRotation" ), QStringLiteral( "0" ) ).toDouble();
501  d->offset = QPointF( backgroundElem.attribute( QStringLiteral( "shapeOffsetX" ), QStringLiteral( "0" ) ).toDouble(),
502  backgroundElem.attribute( QStringLiteral( "shapeOffsetY" ), QStringLiteral( "0" ) ).toDouble() );
503 
504  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeOffsetUnit" ) ) )
505  {
506  d->offsetUnits = QgsTextRendererUtils::convertFromOldLabelUnit( backgroundElem.attribute( QStringLiteral( "shapeOffsetUnits" ) ).toUInt() );
507  }
508  else
509  {
510  d->offsetUnits = QgsUnitTypes::decodeRenderUnit( backgroundElem.attribute( QStringLiteral( "shapeOffsetUnit" ) ) );
511  }
512 
513  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeOffsetMapUnitScale" ) ) )
514  {
515  //fallback to older property
516  double oldMin = backgroundElem.attribute( QStringLiteral( "shapeOffsetMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
517  d->offsetMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
518  double oldMax = backgroundElem.attribute( QStringLiteral( "shapeOffsetMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
519  d->offsetMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
520  }
521  else
522  {
523  d->offsetMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( backgroundElem.attribute( QStringLiteral( "shapeOffsetMapUnitScale" ) ) );
524  }
525  d->radii = QSizeF( backgroundElem.attribute( QStringLiteral( "shapeRadiiX" ), QStringLiteral( "0" ) ).toDouble(),
526  backgroundElem.attribute( QStringLiteral( "shapeRadiiY" ), QStringLiteral( "0" ) ).toDouble() );
527 
528  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeRadiiUnit" ) ) )
529  {
530  d->radiiUnits = QgsTextRendererUtils::convertFromOldLabelUnit( backgroundElem.attribute( QStringLiteral( "shapeRadiiUnits" ) ).toUInt() );
531  }
532  else
533  {
534  d->radiiUnits = QgsUnitTypes::decodeRenderUnit( backgroundElem.attribute( QStringLiteral( "shapeRadiiUnit" ) ) );
535  }
536  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeRadiiMapUnitScale" ) ) )
537  {
538  //fallback to older property
539  double oldMin = backgroundElem.attribute( QStringLiteral( "shapeRadiiMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
540  d->radiiMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
541  double oldMax = backgroundElem.attribute( QStringLiteral( "shapeRadiiMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
542  d->radiiMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
543  }
544  else
545  {
546  d->radiiMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( backgroundElem.attribute( QStringLiteral( "shapeRadiiMapUnitScale" ) ) );
547  }
548  d->fillColor = QgsSymbolLayerUtils::decodeColor( backgroundElem.attribute( QStringLiteral( "shapeFillColor" ), QgsSymbolLayerUtils::encodeColor( Qt::white ) ) );
549  d->strokeColor = QgsSymbolLayerUtils::decodeColor( backgroundElem.attribute( QStringLiteral( "shapeBorderColor" ), QgsSymbolLayerUtils::encodeColor( Qt::darkGray ) ) );
550  d->strokeWidth = backgroundElem.attribute( QStringLiteral( "shapeBorderWidth" ), QStringLiteral( "0" ) ).toDouble();
551 
552  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeBorderWidthUnit" ) ) )
553  {
554  d->strokeWidthUnits = QgsTextRendererUtils::convertFromOldLabelUnit( backgroundElem.attribute( QStringLiteral( "shapeBorderWidthUnits" ) ).toUInt() );
555  }
556  else
557  {
558  d->strokeWidthUnits = QgsUnitTypes::decodeRenderUnit( backgroundElem.attribute( QStringLiteral( "shapeBorderWidthUnit" ) ) );
559  }
560  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeBorderWidthMapUnitScale" ) ) )
561  {
562  //fallback to older property
563  double oldMin = backgroundElem.attribute( QStringLiteral( "shapeBorderWidthMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
564  d->strokeWidthMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
565  double oldMax = backgroundElem.attribute( QStringLiteral( "shapeBorderWidthMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
566  d->strokeWidthMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
567  }
568  else
569  {
570  d->strokeWidthMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( backgroundElem.attribute( QStringLiteral( "shapeBorderWidthMapUnitScale" ) ) );
571  }
572  d->joinStyle = static_cast< Qt::PenJoinStyle >( backgroundElem.attribute( QStringLiteral( "shapeJoinStyle" ), QString::number( Qt::BevelJoin ) ).toUInt() );
573 
574  if ( !backgroundElem.hasAttribute( QStringLiteral( "shapeOpacity" ) ) )
575  {
576  d->opacity = ( 1 - backgroundElem.attribute( QStringLiteral( "shapeTransparency" ) ).toInt() / 100.0 ); //0 -100
577  }
578  else
579  {
580  d->opacity = ( backgroundElem.attribute( QStringLiteral( "shapeOpacity" ) ).toDouble() );
581  }
582 
583  d->blendMode = QgsPainting::getCompositionMode(
584  static_cast< QgsPainting::BlendMode >( backgroundElem.attribute( QStringLiteral( "shapeBlendMode" ), QString::number( QgsPainting::BlendNormal ) ).toUInt() ) );
585 
586  QDomElement effectElem = backgroundElem.firstChildElement( QStringLiteral( "effect" ) );
587  if ( !effectElem.isNull() )
588  setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
589  else
590  setPaintEffect( nullptr );
591 
592  const QDomElement symbolElem = backgroundElem.firstChildElement( QStringLiteral( "symbol" ) );
593  if ( !symbolElem.isNull() )
594  setMarkerSymbol( QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( symbolElem, context ) );
595  else
596  setMarkerSymbol( nullptr );
597 }
598 
599 QDomElement QgsTextBackgroundSettings::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
600 {
601  QDomElement backgroundElem = doc.createElement( QStringLiteral( "background" ) );
602  backgroundElem.setAttribute( QStringLiteral( "shapeDraw" ), d->enabled );
603  backgroundElem.setAttribute( QStringLiteral( "shapeType" ), static_cast< unsigned int >( d->type ) );
604  backgroundElem.setAttribute( QStringLiteral( "shapeSVGFile" ), QgsSymbolLayerUtils::svgSymbolPathToName( d->svgFile, context.pathResolver() ) );
605  backgroundElem.setAttribute( QStringLiteral( "shapeSizeType" ), static_cast< unsigned int >( d->sizeType ) );
606  backgroundElem.setAttribute( QStringLiteral( "shapeSizeX" ), d->size.width() );
607  backgroundElem.setAttribute( QStringLiteral( "shapeSizeY" ), d->size.height() );
608  backgroundElem.setAttribute( QStringLiteral( "shapeSizeUnit" ), QgsUnitTypes::encodeUnit( d->sizeUnits ) );
609  backgroundElem.setAttribute( QStringLiteral( "shapeSizeMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->sizeMapUnitScale ) );
610  backgroundElem.setAttribute( QStringLiteral( "shapeRotationType" ), static_cast< unsigned int >( d->rotationType ) );
611  backgroundElem.setAttribute( QStringLiteral( "shapeRotation" ), d->rotation );
612  backgroundElem.setAttribute( QStringLiteral( "shapeOffsetX" ), d->offset.x() );
613  backgroundElem.setAttribute( QStringLiteral( "shapeOffsetY" ), d->offset.y() );
614  backgroundElem.setAttribute( QStringLiteral( "shapeOffsetUnit" ), QgsUnitTypes::encodeUnit( d->offsetUnits ) );
615  backgroundElem.setAttribute( QStringLiteral( "shapeOffsetMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->offsetMapUnitScale ) );
616  backgroundElem.setAttribute( QStringLiteral( "shapeRadiiX" ), d->radii.width() );
617  backgroundElem.setAttribute( QStringLiteral( "shapeRadiiY" ), d->radii.height() );
618  backgroundElem.setAttribute( QStringLiteral( "shapeRadiiUnit" ), QgsUnitTypes::encodeUnit( d->radiiUnits ) );
619  backgroundElem.setAttribute( QStringLiteral( "shapeRadiiMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->radiiMapUnitScale ) );
620  backgroundElem.setAttribute( QStringLiteral( "shapeFillColor" ), QgsSymbolLayerUtils::encodeColor( d->fillColor ) );
621  backgroundElem.setAttribute( QStringLiteral( "shapeBorderColor" ), QgsSymbolLayerUtils::encodeColor( d->strokeColor ) );
622  backgroundElem.setAttribute( QStringLiteral( "shapeBorderWidth" ), d->strokeWidth );
623  backgroundElem.setAttribute( QStringLiteral( "shapeBorderWidthUnit" ), QgsUnitTypes::encodeUnit( d->strokeWidthUnits ) );
624  backgroundElem.setAttribute( QStringLiteral( "shapeBorderWidthMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->strokeWidthMapUnitScale ) );
625  backgroundElem.setAttribute( QStringLiteral( "shapeJoinStyle" ), static_cast< unsigned int >( d->joinStyle ) );
626  backgroundElem.setAttribute( QStringLiteral( "shapeOpacity" ), d->opacity );
627  backgroundElem.setAttribute( QStringLiteral( "shapeBlendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) );
628  if ( d->paintEffect && !QgsPaintEffectRegistry::isDefaultStack( d->paintEffect.get() ) )
629  d->paintEffect->saveProperties( doc, backgroundElem );
630 
631  if ( d->markerSymbol )
632  backgroundElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "markerSymbol" ), d->markerSymbol.get(), doc, context ) );
633 
634  return backgroundElem;
635 }
636 
638 {
639  if ( properties.isActive( QgsPalLayerSettings::ShapeDraw ) )
640  {
641  context.expressionContext().setOriginalValueVariable( d->enabled );
642  d->enabled = properties.valueAsBool( QgsPalLayerSettings::ShapeDraw, context.expressionContext(), d->enabled );
643  }
644 
645  if ( properties.isActive( QgsPalLayerSettings::ShapeSizeX ) )
646  {
647  context.expressionContext().setOriginalValueVariable( d->size.width() );
648  d->size.setWidth( properties.valueAsDouble( QgsPalLayerSettings::ShapeSizeX, context.expressionContext(), d->size.width() ) );
649  }
650  if ( properties.isActive( QgsPalLayerSettings::ShapeSizeY ) )
651  {
652  context.expressionContext().setOriginalValueVariable( d->size.height() );
653  d->size.setHeight( properties.valueAsDouble( QgsPalLayerSettings::ShapeSizeY, context.expressionContext(), d->size.height() ) );
654  }
655 
656  QVariant exprVal = properties.value( QgsPalLayerSettings::ShapeSizeUnits, context.expressionContext() );
657  if ( exprVal.isValid() )
658  {
659  QString units = exprVal.toString();
660  if ( !units.isEmpty() )
661  {
662  bool ok;
664  if ( ok )
665  d->sizeUnits = res;
666  }
667  }
668 
669  exprVal = properties.value( QgsPalLayerSettings::ShapeKind, context.expressionContext() );
670  if ( exprVal.isValid() )
671  {
672  const QString skind = exprVal.toString().trimmed();
673  if ( !skind.isEmpty() )
674  {
675  d->type = QgsTextRendererUtils::decodeShapeType( skind );
676  }
677  }
678 
679  exprVal = properties.value( QgsPalLayerSettings::ShapeSizeType, context.expressionContext() );
680  if ( exprVal.isValid() )
681  {
682  QString stype = exprVal.toString().trimmed();
683  if ( !stype.isEmpty() )
684  {
685  d->sizeType = QgsTextRendererUtils::decodeBackgroundSizeType( stype );
686  }
687  }
688 
689  // data defined shape SVG path?
690  context.expressionContext().setOriginalValueVariable( d->svgFile );
691  exprVal = properties.value( QgsPalLayerSettings::ShapeSVGFile, context.expressionContext() );
692  if ( exprVal.isValid() )
693  {
694  QString svgfile = exprVal.toString().trimmed();
695  d->svgFile = QgsSymbolLayerUtils::svgSymbolNameToPath( svgfile, context.pathResolver() );
696  }
697 
698  if ( properties.isActive( QgsPalLayerSettings::ShapeRotation ) )
699  {
700  context.expressionContext().setOriginalValueVariable( d->rotation );
701  d->rotation = properties.valueAsDouble( QgsPalLayerSettings::ShapeRotation, context.expressionContext(), d->rotation );
702  }
703  exprVal = properties.value( QgsPalLayerSettings::ShapeRotationType, context.expressionContext() );
704  if ( exprVal.isValid() )
705  {
706  QString rotstr = exprVal.toString().trimmed();
707  if ( !rotstr.isEmpty() )
708  {
709  d->rotationType = QgsTextRendererUtils::decodeBackgroundRotationType( rotstr );
710  }
711  }
712 
713  exprVal = properties.value( QgsPalLayerSettings::ShapeOffset, context.expressionContext() );
714  if ( exprVal.isValid() )
715  {
716  bool ok = false;
717  const QPointF res = QgsSymbolLayerUtils::toPoint( exprVal, &ok );
718  if ( ok )
719  {
720  d->offset = res;
721  }
722  }
723  exprVal = properties.value( QgsPalLayerSettings::ShapeOffsetUnits, context.expressionContext() );
724  if ( exprVal.isValid() )
725  {
726  QString units = exprVal.toString();
727  if ( !units.isEmpty() )
728  {
729  bool ok;
731  if ( ok )
732  d->offsetUnits = res;
733  }
734  }
735 
736  exprVal = properties.value( QgsPalLayerSettings::ShapeRadii, context.expressionContext() );
737  if ( exprVal.isValid() )
738  {
739  bool ok = false;
740  const QSizeF res = QgsSymbolLayerUtils::toSize( exprVal, &ok );
741  if ( ok )
742  {
743  d->radii = res;
744  }
745  }
746 
747  exprVal = properties.value( QgsPalLayerSettings::ShapeRadiiUnits, context.expressionContext() );
748  if ( exprVal.isValid() )
749  {
750  QString units = exprVal.toString();
751  if ( !units.isEmpty() )
752  {
753  bool ok;
755  if ( ok )
756  d->radiiUnits = res;
757  }
758  }
759 
760  if ( properties.isActive( QgsPalLayerSettings::ShapeOpacity ) )
761  {
762  context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
763  d->opacity = properties.value( QgsPalLayerSettings::ShapeOpacity, context.expressionContext(), d->opacity * 100 ).toDouble() / 100.0;
764  }
765 
766  if ( properties.isActive( QgsPalLayerSettings::ShapeFillColor ) )
767  {
769  d->fillColor = properties.valueAsColor( QgsPalLayerSettings::ShapeFillColor, context.expressionContext(), d->fillColor );
770  }
772  {
774  d->strokeColor = properties.valueAsColor( QgsPalLayerSettings::ShapeStrokeColor, context.expressionContext(), d->strokeColor );
775  }
776 
778  {
779  context.expressionContext().setOriginalValueVariable( d->strokeWidth );
780  d->strokeWidth = properties.valueAsDouble( QgsPalLayerSettings::ShapeStrokeWidth, context.expressionContext(), d->strokeWidth );
781  }
782  exprVal = properties.value( QgsPalLayerSettings::ShapeStrokeWidthUnits, context.expressionContext() );
783  if ( exprVal.isValid() )
784  {
785  QString units = exprVal.toString();
786  if ( !units.isEmpty() )
787  {
788  bool ok;
790  if ( ok )
791  d->strokeWidthUnits = res;
792  }
793  }
794 
795  if ( properties.isActive( QgsPalLayerSettings::ShapeBlendMode ) )
796  {
797  exprVal = properties.value( QgsPalLayerSettings::ShapeBlendMode, context.expressionContext() );
798  QString blendstr = exprVal.toString().trimmed();
799  if ( !blendstr.isEmpty() )
800  d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
801  }
802 
803  if ( properties.isActive( QgsPalLayerSettings::ShapeJoinStyle ) )
804  {
805  exprVal = properties.value( QgsPalLayerSettings::ShapeJoinStyle, context.expressionContext() );
806  QString joinstr = exprVal.toString().trimmed();
807  if ( !joinstr.isEmpty() )
808  {
809  d->joinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( joinstr );
810  }
811  }
812 }
813 
815 {
816  QSet< QString > fields;
817  if ( d->markerSymbol )
818  {
819  fields.unite( d->markerSymbol->usedAttributes( context ) );
820  }
821  return fields;
822 }
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.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:1004
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
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
@ ShapeOpacity
Shape 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.
The class is used as a container of context for various read/write operations on other objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
Contains information about the context of a rendering operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsPathResolver & pathResolver() const
Returns the path resolver for conversion between relative and absolute paths during rendering operati...
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QColor decodeColor(const QString &str)
static QString svgSymbolPathToName(const QString &path, const QgsPathResolver &pathResolver)
Determines an SVG symbol's name from its path.
static QPointF toPoint(const QVariant &value, bool *ok=nullptr)
Converts a value to a point.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static QSizeF toSize(const QVariant &value, bool *ok=nullptr)
Converts a value to a size.
static QPainter::CompositionMode decodeBlendMode(const QString &s)
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
static QString encodeColor(const QColor &color)
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
static QString symbolProperties(QgsSymbol *symbol)
Returns a string representing the symbol.
Container for settings relating to a text background object.
QgsMapUnitScale strokeWidthMapUnitScale() const
Returns the map unit scale object for the shape stroke width.
RotationType rotationType() const
Returns the method used for rotating the background shape.
QString svgFile() const
Returns the absolute path to the background SVG file, if set.
QSizeF size() const
Returns the size of the background shape.
QSizeF radii() const
Returns the radii used for rounding the corners of shapes.
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
QgsMapUnitScale radiiMapUnitScale() const
Returns the map unit scale object for the shape radii.
void setOpacity(double opacity)
Sets the background shape's opacity.
void setStrokeColor(const QColor &color)
Sets the color used for outlining the background shape.
QgsUnitTypes::RenderUnit strokeWidthUnit() const
Returns the units used for the shape's stroke width.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape size.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the background shape.
Qt::PenJoinStyle joinStyle() const
Returns the join style used for drawing the background shape.
SizeType
Methods for determining the background shape size.
@ SizeBuffer
Shape size is determined by adding a buffer margin around text.
bool enabled() const
Returns whether the background is enabled.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the background shape.
void setRadiiUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's radii.
double opacity() const
Returns the background shape's opacity.
bool operator!=(const QgsTextBackgroundSettings &other) const
void updateDataDefinedProperties(QgsRenderContext &context, const QgsPropertyCollection &properties)
Updates the format by evaluating current values of data defined properties.
void setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape stroke width.
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units used for the shape's offset.
double rotation() const
Returns the rotation for the background shape, in degrees clockwise.
QColor fillColor() const
Returns the color used for filing the background shape.
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the current marker symbol for the background shape.
void setRadii(QSizeF radii)
Sets the radii used for rounding the corners of shapes.
SizeType sizeType() const
Returns the method used to determine the size of the background shape (e.g., fixed size or buffer aro...
QgsTextBackgroundSettings & operator=(const QgsTextBackgroundSettings &other)
ShapeType type() const
Returns the type of background shape (e.g., square, ellipse, SVG).
double strokeWidth() const
Returns the width of the shape's stroke (stroke).
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
ShapeType
Background shape types.
void setFillColor(const QColor &color)
Sets the color used for filing the background shape.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the background shape.
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's stroke width.
QColor strokeColor() const
Returns the color used for outlining the background shape.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
void setRotationType(RotationType type)
Sets the method used for rotating the background shape.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape offset.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the background shape.
void readFromLayer(QgsVectorLayer *layer)
Reads settings from a layer's custom properties (for QGIS 2.x projects).
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the shape size.
void setType(ShapeType type)
Sets the type of background shape to draw (e.g., square, ellipse, SVG).
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units used for the shape's size.
RotationType
Methods for determining the rotation of the background shape.
@ RotationSync
Shape rotation is synced with text rotation.
bool operator==(const QgsTextBackgroundSettings &other) const
QgsUnitTypes::RenderUnit radiiUnit() const
Returns the units used for the shape's radii.
void setEnabled(bool enabled)
Sets whether the text background will be drawn.
QgsMarkerSymbol * markerSymbol() const
Returns the marker symbol to be rendered in the background.
void setRadiiMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape radii.
void setRotation(double rotation)
Sets the rotation for the background shape, in degrees clockwise.
void setOffset(QPointF offset)
Sets the offset used for drawing the background shape.
void setSize(QSizeF size)
Sets the size of the background shape.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the shape's size.
const QgsPaintEffect * paintEffect() const
Returns the current paint effect for the background shape.
void setSvgFile(const QString &file)
Sets the path to the background SVG file.
QgsMapUnitScale offsetMapUnitScale() const
Returns the map unit scale object for the shape offset.
void setStrokeWidth(double width)
Sets the width of the shape's stroke (stroke).
QPointF offset() const
Returns the offset used for drawing the background shape.
void setOffsetUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's offset.
static QgsTextBackgroundSettings::ShapeType decodeShapeType(const QString &string)
Decodes a string representation of a background shape type to a type.
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 QgsTextBackgroundSettings::RotationType decodeBackgroundRotationType(const QString &string)
Decodes a string representation of a background rotation type to a type.
static QgsTextBackgroundSettings::SizeType decodeBackgroundSizeType(const QString &string)
Decodes a string representation of a background size type to a type.
static QgsUnitTypes::RenderUnit convertFromOldLabelUnit(int val)
Converts a unit from an old (pre 3.0) label unit.
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:167
Represents a vector layer which manages a vector based data sets.