QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgstextformat.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstextformat.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 
16 #include "qgstextformat.h"
17 #include "qgstextrenderer_p.h"
18 #include "qgstextrenderer.h"
19 #include "qgsvectorlayer.h"
20 #include "qgsfontutils.h"
21 #include "qgssymbollayerutils.h"
22 #include "qgspainting.h"
23 #include "qgstextrendererutils.h"
24 #include "qgspallabeling.h"
25 #include "qgsconfig.h"
26 #include <QFontDatabase>
27 #include <QMimeData>
28 #include <QWidget>
29 #include <QScreen>
30 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
31 #include <QDesktopWidget>
32 #endif
33 
35 {
36  d = new QgsTextSettingsPrivate();
37 }
38 
40  : mBufferSettings( other.mBufferSettings )
41  , mBackgroundSettings( other.mBackgroundSettings )
42  , mShadowSettings( other.mShadowSettings )
43  , mMaskSettings( other.mMaskSettings )
44  , mTextFontFamily( other.mTextFontFamily )
45  , mTextFontFound( other.mTextFontFound )
46  , d( other.d )
47 {
48 
49 }
50 
52 {
53  d = other.d;
54  mBufferSettings = other.mBufferSettings;
55  mBackgroundSettings = other.mBackgroundSettings;
56  mShadowSettings = other.mShadowSettings;
57  mMaskSettings = other.mMaskSettings;
58  mTextFontFamily = other.mTextFontFamily;
59  mTextFontFound = other.mTextFontFound;
60  return *this;
61 }
62 
64 {
65 
66 }
67 
68 bool QgsTextFormat::operator==( const QgsTextFormat &other ) const
69 {
70  if ( d->isValid != other.isValid()
71  || d->textFont != other.font()
72  || namedStyle() != other.namedStyle()
73  || d->fontSizeUnits != other.sizeUnit()
74  || d->fontSizeMapUnitScale != other.sizeMapUnitScale()
75  || d->fontSize != other.size()
76  || d->textColor != other.color()
77  || d->opacity != other.opacity()
78  || d->blendMode != other.blendMode()
79  || d->multilineHeight != other.lineHeight()
80  || d->orientation != other.orientation()
81  || d->previewBackgroundColor != other.previewBackgroundColor()
82  || d->allowHtmlFormatting != other.allowHtmlFormatting()
83  || d->capitalization != other.capitalization()
84  || mBufferSettings != other.mBufferSettings
85  || mBackgroundSettings != other.mBackgroundSettings
86  || mShadowSettings != other.mShadowSettings
87  || mMaskSettings != other.mMaskSettings
88  || d->families != other.families()
89  || d->mDataDefinedProperties != other.dataDefinedProperties() )
90  return false;
91 
92  return true;
93 }
94 
95 bool QgsTextFormat::operator!=( const QgsTextFormat &other ) const
96 {
97  return !( *this == other );
98 }
99 
101 {
102  return d->isValid;
103 }
104 
106 {
107  d->isValid = true;
108 }
109 
111 {
112  d->isValid = true;
113  return mBufferSettings;
114 }
115 
116 void QgsTextFormat::setBuffer( const QgsTextBufferSettings &bufferSettings )
117 {
118  d->isValid = true;
119  mBufferSettings = bufferSettings;
120 }
121 
123 {
124  d->isValid = true;
125  return mBackgroundSettings;
126 }
127 
129 {
130  d->isValid = true;
131  mBackgroundSettings = backgroundSettings;
132 }
133 
135 {
136  d->isValid = true;
137  return mShadowSettings;
138 }
139 
140 void QgsTextFormat::setShadow( const QgsTextShadowSettings &shadowSettings )
141 {
142  d->isValid = true;
143  mShadowSettings = shadowSettings;
144 }
145 
147 {
148  d->isValid = true;
149  return mMaskSettings;
150 }
151 
152 void QgsTextFormat::setMask( const QgsTextMaskSettings &maskSettings )
153 {
154  d->isValid = true;
155  mMaskSettings = maskSettings;
156 }
157 
158 QFont QgsTextFormat::font() const
159 {
160  return d->textFont;
161 }
162 
163 QFont QgsTextFormat::scaledFont( const QgsRenderContext &context, double scaleFactor, bool *isZeroSize ) const
164 {
165  if ( isZeroSize )
166  *isZeroSize = false;
167 
168  QFont font = d->textFont;
169  if ( scaleFactor == 1 )
170  {
171  int fontPixelSize = QgsTextRenderer::sizeToPixel( d->fontSize, context, d->fontSizeUnits,
172  d->fontSizeMapUnitScale );
173  if ( fontPixelSize == 0 )
174  {
175  if ( isZeroSize )
176  *isZeroSize = true;
177  return QFont();
178  }
179 
180  font.setPixelSize( fontPixelSize );
181  }
182  else
183  {
184  double fontPixelSize = context.convertToPainterUnits( d->fontSize, d->fontSizeUnits, d->fontSizeMapUnitScale );
185  if ( qgsDoubleNear( fontPixelSize, 0 ) )
186  {
187  if ( isZeroSize )
188  *isZeroSize = true;
189  return QFont();
190  }
191  const int roundedPixelSize = static_cast< int >( std::round( scaleFactor * fontPixelSize + 0.5 ) );
192  font.setPixelSize( roundedPixelSize );
193  }
194 
195  font.setLetterSpacing( QFont::AbsoluteSpacing, context.convertToPainterUnits( d->textFont.letterSpacing(), d->fontSizeUnits, d->fontSizeMapUnitScale ) * scaleFactor );
196  font.setWordSpacing( context.convertToPainterUnits( d->textFont.wordSpacing(), d->fontSizeUnits, d->fontSizeMapUnitScale ) * scaleFactor * scaleFactor );
197 
198  if ( d->capitalization == Qgis::Capitalization::SmallCaps
199  || d->capitalization == Qgis::Capitalization::AllSmallCaps )
200  font.setCapitalization( QFont::SmallCaps );
201 
202  return font;
203 }
204 
205 void QgsTextFormat::setFont( const QFont &font )
206 {
207  d->isValid = true;
208  d->textFont = font;
209 }
210 
212 {
213  if ( !d->textNamedStyle.isEmpty() )
214  return d->textNamedStyle;
215 
216  QFontDatabase db;
217  return db.styleString( d->textFont );
218 }
219 
220 void QgsTextFormat::setNamedStyle( const QString &style )
221 {
222  d->isValid = true;
223  QgsFontUtils::updateFontViaStyle( d->textFont, style );
224  d->textNamedStyle = style;
225 }
226 
227 QStringList QgsTextFormat::families() const
228 {
229  return d->families;
230 }
231 
232 void QgsTextFormat::setFamilies( const QStringList &families )
233 {
234  d->isValid = true;
235  d->families = families;
236 }
237 
239 {
240  return d->fontSizeUnits;
241 }
242 
244 {
245  d->isValid = true;
246  d->fontSizeUnits = unit;
247 }
248 
250 {
251  return d->fontSizeMapUnitScale;
252 }
253 
255 {
256  d->isValid = true;
257  d->fontSizeMapUnitScale = scale;
258 }
259 
260 double QgsTextFormat::size() const
261 {
262  return d->fontSize;
263 }
264 
265 void QgsTextFormat::setSize( double size )
266 {
267  d->isValid = true;
268  d->fontSize = size;
269 }
270 
271 QColor QgsTextFormat::color() const
272 {
273  return d->textColor;
274 }
275 
276 void QgsTextFormat::setColor( const QColor &color )
277 {
278  d->isValid = true;
279  d->textColor = color;
280 }
281 
283 {
284  return d->opacity;
285 }
286 
287 void QgsTextFormat::setOpacity( double opacity )
288 {
289  d->isValid = true;
290  d->opacity = opacity;
291 }
292 
294 {
295  return d->textFont.stretch() > 0 ? d->textFont.stretch() : 100;
296 }
297 
299 {
300  d->isValid = true;
301  d->textFont.setStretch( factor );
302 }
303 
304 QPainter::CompositionMode QgsTextFormat::blendMode() const
305 {
306  return d->blendMode;
307 }
308 
309 void QgsTextFormat::setBlendMode( QPainter::CompositionMode mode )
310 {
311  d->isValid = true;
312  d->blendMode = mode;
313 }
314 
316 {
317  return d->multilineHeight;
318 }
319 
320 void QgsTextFormat::setLineHeight( double height )
321 {
322  d->isValid = true;
323  d->multilineHeight = height;
324 }
325 
327 {
328  return d->orientation;
329 }
330 
332 {
333  d->isValid = true;
334  d->orientation = orientation;
335 }
336 
338 {
339  // bit of complexity here to maintain API..
340  return d->capitalization == Qgis::Capitalization::MixedCase && d->textFont.capitalization() != QFont::MixedCase
341  ? static_cast< Qgis::Capitalization >( d->textFont.capitalization() )
342  : d->capitalization ;
343 }
344 
346 {
347  d->isValid = true;
348  d->capitalization = capitalization;
349 #if defined(HAS_KDE_QT5_SMALL_CAPS_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
350  d->textFont.setCapitalization( capitalization == Qgis::Capitalization::SmallCaps || capitalization == Qgis::Capitalization::AllSmallCaps ? QFont::SmallCaps : QFont::MixedCase );
351 #else
352  d->textFont.setCapitalization( QFont::MixedCase );
353 #endif
354 }
355 
357 {
358  return d->allowHtmlFormatting;
359 }
360 
362 {
363  d->isValid = true;
364  d->allowHtmlFormatting = allow;
365 }
366 
368 {
369  return d->previewBackgroundColor;
370 }
371 
372 void QgsTextFormat::setPreviewBackgroundColor( const QColor &color )
373 {
374  d->isValid = true;
375  d->previewBackgroundColor = color;
376 }
377 
379 {
380  d->isValid = true;
381  QFont appFont = QApplication::font();
382  mTextFontFamily = layer->customProperty( QStringLiteral( "labeling/fontFamily" ), QVariant( appFont.family() ) ).toString();
383  QString fontFamily = mTextFontFamily;
384  if ( mTextFontFamily != appFont.family() && !QgsFontUtils::fontFamilyMatchOnSystem( mTextFontFamily ) )
385  {
386  // trigger to notify about font family substitution
387  mTextFontFound = false;
388 
389  // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
390  // currently only defaults to matching algorithm for resolving [foundry], if a font of similar family is found (default for QFont)
391 
392  // for now, do not use matching algorithm for substitution if family not found, substitute default instead
393  fontFamily = appFont.family();
394  }
395  else
396  {
397  mTextFontFound = true;
398  }
399 
400  if ( !layer->customProperty( QStringLiteral( "labeling/fontSize" ) ).isValid() )
401  {
402  d->fontSize = appFont.pointSizeF();
403  }
404  else
405  {
406  d->fontSize = layer->customProperty( QStringLiteral( "labeling/fontSize" ) ).toDouble();
407  }
408 
409  if ( layer->customProperty( QStringLiteral( "labeling/fontSizeUnit" ) ).toString().isEmpty() )
410  {
411  d->fontSizeUnits = layer->customProperty( QStringLiteral( "labeling/fontSizeInMapUnits" ), QVariant( false ) ).toBool() ?
413  }
414  else
415  {
416  bool ok = false;
417  d->fontSizeUnits = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/fontSizeUnit" ) ).toString(), &ok );
418  if ( !ok )
419  d->fontSizeUnits = QgsUnitTypes::RenderPoints;
420  }
421  if ( layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitScale" ) ).toString().isEmpty() )
422  {
423  //fallback to older property
424  double oldMin = layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitMinScale" ), 0.0 ).toDouble();
425  d->fontSizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
426  double oldMax = layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitMaxScale" ), 0.0 ).toDouble();
427  d->fontSizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
428  }
429  else
430  {
431  d->fontSizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitScale" ) ).toString() );
432  }
433  int fontWeight = layer->customProperty( QStringLiteral( "labeling/fontWeight" ) ).toInt();
434  bool fontItalic = layer->customProperty( QStringLiteral( "labeling/fontItalic" ) ).toBool();
435  d->textFont = QFont( fontFamily, d->fontSize, fontWeight, fontItalic );
436  d->textNamedStyle = QgsFontUtils::translateNamedStyle( layer->customProperty( QStringLiteral( "labeling/namedStyle" ), QVariant( "" ) ).toString() );
437  QgsFontUtils::updateFontViaStyle( d->textFont, d->textNamedStyle ); // must come after textFont.setPointSizeF()
438  d->capitalization = static_cast< Qgis::Capitalization >( layer->customProperty( QStringLiteral( "labeling/fontCapitals" ), QVariant( 0 ) ).toUInt() );
439  d->textFont.setUnderline( layer->customProperty( QStringLiteral( "labeling/fontUnderline" ) ).toBool() );
440  d->textFont.setStrikeOut( layer->customProperty( QStringLiteral( "labeling/fontStrikeout" ) ).toBool() );
441  d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, layer->customProperty( QStringLiteral( "labeling/fontLetterSpacing" ), QVariant( 0.0 ) ).toDouble() );
442  d->textFont.setWordSpacing( layer->customProperty( QStringLiteral( "labeling/fontWordSpacing" ), QVariant( 0.0 ) ).toDouble() );
443  d->textColor = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/textColor" ), Qt::black, false );
444  if ( layer->customProperty( QStringLiteral( "labeling/textOpacity" ) ).toString().isEmpty() )
445  {
446  d->opacity = ( 1 - layer->customProperty( QStringLiteral( "labeling/textTransp" ) ).toInt() / 100.0 ); //0 -100
447  }
448  else
449  {
450  d->opacity = ( layer->customProperty( QStringLiteral( "labeling/textOpacity" ) ).toDouble() );
451  }
452  d->blendMode = QgsPainting::getCompositionMode(
453  static_cast< QgsPainting::BlendMode >( layer->customProperty( QStringLiteral( "labeling/blendMode" ), QVariant( QgsPainting::BlendNormal ) ).toUInt() ) );
454  d->multilineHeight = layer->customProperty( QStringLiteral( "labeling/multilineHeight" ), QVariant( 1.0 ) ).toDouble();
455  d->previewBackgroundColor = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/previewBkgrdColor" ), QColor( 255, 255, 255 ), false );
456 
457  mBufferSettings.readFromLayer( layer );
458  mShadowSettings.readFromLayer( layer );
459  mBackgroundSettings.readFromLayer( layer );
460 }
461 
462 void QgsTextFormat::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
463 {
464  d->isValid = true;
465  QDomElement textStyleElem;
466  if ( elem.nodeName() == QLatin1String( "text-style" ) )
467  textStyleElem = elem;
468  else
469  textStyleElem = elem.firstChildElement( QStringLiteral( "text-style" ) );
470  QFont appFont = QApplication::font();
471  mTextFontFamily = textStyleElem.attribute( QStringLiteral( "fontFamily" ), appFont.family() );
472  QString fontFamily = mTextFontFamily;
473 
474  const QDomElement familiesElem = textStyleElem.firstChildElement( QStringLiteral( "families" ) );
475  const QDomNodeList familyNodes = familiesElem.childNodes();
476  QStringList families;
477  families.reserve( familyNodes.size() );
478  for ( int i = 0; i < familyNodes.count(); ++i )
479  {
480  const QDomElement familyElem = familyNodes.at( i ).toElement();
481  families << familyElem.attribute( QStringLiteral( "name" ) );
482  }
483  d->families = families;
484 
485  mTextFontFound = false;
486  if ( mTextFontFamily != appFont.family() && !QgsFontUtils::fontFamilyMatchOnSystem( mTextFontFamily ) )
487  {
488  for ( const QString &family : std::as_const( families ) )
489  {
491  {
492  mTextFontFound = true;
493  fontFamily = family;
494  break;
495  }
496  }
497 
498  if ( !mTextFontFound )
499  {
500  // couldn't even find a matching font in the backup list -- substitute default instead
501  fontFamily = appFont.family();
502  }
503  }
504  else
505  {
506  mTextFontFound = true;
507  }
508 
509  if ( !mTextFontFound )
510  {
511  context.pushMessage( QObject::tr( "Font “%1” not available on system" ).arg( mTextFontFamily ) );
512  }
513 
514  if ( textStyleElem.hasAttribute( QStringLiteral( "fontSize" ) ) )
515  {
516  d->fontSize = textStyleElem.attribute( QStringLiteral( "fontSize" ) ).toDouble();
517  }
518  else
519  {
520  d->fontSize = appFont.pointSizeF();
521  }
522 
523  if ( !textStyleElem.hasAttribute( QStringLiteral( "fontSizeUnit" ) ) )
524  {
525  d->fontSizeUnits = textStyleElem.attribute( QStringLiteral( "fontSizeInMapUnits" ) ).toUInt() == 0 ? QgsUnitTypes::RenderPoints
527  }
528  else
529  {
530  d->fontSizeUnits = QgsUnitTypes::decodeRenderUnit( textStyleElem.attribute( QStringLiteral( "fontSizeUnit" ) ) );
531  }
532 
533  if ( !textStyleElem.hasAttribute( QStringLiteral( "fontSizeMapUnitScale" ) ) )
534  {
535  //fallback to older property
536  double oldMin = textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
537  d->fontSizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
538  double oldMax = textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
539  d->fontSizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
540  }
541  else
542  {
543  d->fontSizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitScale" ) ) );
544  }
545  int fontWeight = textStyleElem.attribute( QStringLiteral( "fontWeight" ) ).toInt();
546  bool fontItalic = textStyleElem.attribute( QStringLiteral( "fontItalic" ) ).toInt();
547  d->textFont = QFont( fontFamily, d->fontSize, fontWeight, fontItalic );
548  d->textFont.setPointSizeF( d->fontSize ); //double precision needed because of map units
549  d->textNamedStyle = QgsFontUtils::translateNamedStyle( textStyleElem.attribute( QStringLiteral( "namedStyle" ) ) );
550  QgsFontUtils::updateFontViaStyle( d->textFont, d->textNamedStyle ); // must come after textFont.setPointSizeF()
551  d->textFont.setUnderline( textStyleElem.attribute( QStringLiteral( "fontUnderline" ) ).toInt() );
552  d->textFont.setStrikeOut( textStyleElem.attribute( QStringLiteral( "fontStrikeout" ) ).toInt() );
553  d->textFont.setKerning( textStyleElem.attribute( QStringLiteral( "fontKerning" ), QStringLiteral( "1" ) ).toInt() );
554  d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, textStyleElem.attribute( QStringLiteral( "fontLetterSpacing" ), QStringLiteral( "0" ) ).toDouble() );
555  d->textFont.setWordSpacing( textStyleElem.attribute( QStringLiteral( "fontWordSpacing" ), QStringLiteral( "0" ) ).toDouble() );
556  d->textColor = QgsSymbolLayerUtils::decodeColor( textStyleElem.attribute( QStringLiteral( "textColor" ), QgsSymbolLayerUtils::encodeColor( Qt::black ) ) );
557  if ( !textStyleElem.hasAttribute( QStringLiteral( "textOpacity" ) ) )
558  {
559  d->opacity = ( 1 - textStyleElem.attribute( QStringLiteral( "textTransp" ) ).toInt() / 100.0 ); //0 -100
560  }
561  else
562  {
563  d->opacity = ( textStyleElem.attribute( QStringLiteral( "textOpacity" ) ).toDouble() );
564  }
565 #ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
566  d->textFont.setStretch( textStyleElem.attribute( QStringLiteral( "stretchFactor" ), QStringLiteral( "100" ) ).toInt() );
567 #endif
568  d->orientation = QgsTextRendererUtils::decodeTextOrientation( textStyleElem.attribute( QStringLiteral( "textOrientation" ) ) );
569  d->previewBackgroundColor = QgsSymbolLayerUtils::decodeColor( textStyleElem.attribute( QStringLiteral( "previewBkgrdColor" ), QgsSymbolLayerUtils::encodeColor( Qt::white ) ) );
570 
571  d->blendMode = QgsPainting::getCompositionMode(
572  static_cast< QgsPainting::BlendMode >( textStyleElem.attribute( QStringLiteral( "blendMode" ), QString::number( QgsPainting::BlendNormal ) ).toUInt() ) );
573 
574  if ( !textStyleElem.hasAttribute( QStringLiteral( "multilineHeight" ) ) )
575  {
576  QDomElement textFormatElem = elem.firstChildElement( QStringLiteral( "text-format" ) );
577  d->multilineHeight = textFormatElem.attribute( QStringLiteral( "multilineHeight" ), QStringLiteral( "1" ) ).toDouble();
578  }
579  else
580  {
581  d->multilineHeight = textStyleElem.attribute( QStringLiteral( "multilineHeight" ), QStringLiteral( "1" ) ).toDouble();
582  }
583 
584  if ( textStyleElem.hasAttribute( QStringLiteral( "capitalization" ) ) )
585  d->capitalization = static_cast< Qgis::Capitalization >( textStyleElem.attribute( QStringLiteral( "capitalization" ), QString::number( static_cast< int >( Qgis::Capitalization::MixedCase ) ) ).toInt() );
586  else
587  d->capitalization = static_cast< Qgis::Capitalization >( textStyleElem.attribute( QStringLiteral( "fontCapitals" ), QStringLiteral( "0" ) ).toUInt() );
588 
589  if ( d->capitalization == Qgis::Capitalization::SmallCaps || d->capitalization == Qgis::Capitalization::AllSmallCaps )
590  d->textFont.setCapitalization( QFont::SmallCaps );
591 
592  d->allowHtmlFormatting = textStyleElem.attribute( QStringLiteral( "allowHtml" ), QStringLiteral( "0" ) ).toInt();
593 
594  if ( textStyleElem.firstChildElement( QStringLiteral( "text-buffer" ) ).isNull() )
595  {
596  mBufferSettings.readXml( elem );
597  }
598  else
599  {
600  mBufferSettings.readXml( textStyleElem );
601  }
602  if ( textStyleElem.firstChildElement( QStringLiteral( "text-mask" ) ).isNull() )
603  {
604  mMaskSettings.readXml( elem );
605  }
606  else
607  {
608  mMaskSettings.readXml( textStyleElem );
609  }
610  if ( textStyleElem.firstChildElement( QStringLiteral( "shadow" ) ).isNull() )
611  {
612  mShadowSettings.readXml( elem );
613  }
614  else
615  {
616  mShadowSettings.readXml( textStyleElem );
617  }
618  if ( textStyleElem.firstChildElement( QStringLiteral( "background" ) ).isNull() )
619  {
620  mBackgroundSettings.readXml( elem, context );
621  }
622  else
623  {
624  mBackgroundSettings.readXml( textStyleElem, context );
625  }
626 
627  QDomElement ddElem = textStyleElem.firstChildElement( QStringLiteral( "dd_properties" ) );
628  if ( ddElem.isNull() )
629  {
630  ddElem = elem.firstChildElement( QStringLiteral( "dd_properties" ) );
631  }
632  if ( !ddElem.isNull() )
633  {
634  d->mDataDefinedProperties.readXml( ddElem, QgsPalLayerSettings::propertyDefinitions() );
635  mBackgroundSettings.upgradeDataDefinedProperties( d->mDataDefinedProperties );
636  }
637  else
638  {
639  d->mDataDefinedProperties.clear();
640  }
641 }
642 
643 QDomElement QgsTextFormat::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
644 {
645  // text style
646  QDomElement textStyleElem = doc.createElement( QStringLiteral( "text-style" ) );
647  textStyleElem.setAttribute( QStringLiteral( "fontFamily" ), d->textFont.family() );
648 
649  QDomElement familiesElem = doc.createElement( QStringLiteral( "families" ) );
650  for ( const QString &family : std::as_const( d->families ) )
651  {
652  QDomElement familyElem = doc.createElement( QStringLiteral( "family" ) );
653  familyElem.setAttribute( QStringLiteral( "name" ), family );
654  familiesElem.appendChild( familyElem );
655  }
656  textStyleElem.appendChild( familiesElem );
657 
658  textStyleElem.setAttribute( QStringLiteral( "namedStyle" ), QgsFontUtils::untranslateNamedStyle( d->textNamedStyle ) );
659  textStyleElem.setAttribute( QStringLiteral( "fontSize" ), d->fontSize );
660  textStyleElem.setAttribute( QStringLiteral( "fontSizeUnit" ), QgsUnitTypes::encodeUnit( d->fontSizeUnits ) );
661  textStyleElem.setAttribute( QStringLiteral( "fontSizeMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->fontSizeMapUnitScale ) );
662  textStyleElem.setAttribute( QStringLiteral( "fontWeight" ), d->textFont.weight() );
663  textStyleElem.setAttribute( QStringLiteral( "fontItalic" ), d->textFont.italic() );
664  textStyleElem.setAttribute( QStringLiteral( "fontStrikeout" ), d->textFont.strikeOut() );
665  textStyleElem.setAttribute( QStringLiteral( "fontUnderline" ), d->textFont.underline() );
666  textStyleElem.setAttribute( QStringLiteral( "textColor" ), QgsSymbolLayerUtils::encodeColor( d->textColor ) );
667  textStyleElem.setAttribute( QStringLiteral( "previewBkgrdColor" ), QgsSymbolLayerUtils::encodeColor( d->previewBackgroundColor ) );
668  textStyleElem.setAttribute( QStringLiteral( "fontLetterSpacing" ), d->textFont.letterSpacing() );
669  textStyleElem.setAttribute( QStringLiteral( "fontWordSpacing" ), d->textFont.wordSpacing() );
670  textStyleElem.setAttribute( QStringLiteral( "fontKerning" ), d->textFont.kerning() );
671  textStyleElem.setAttribute( QStringLiteral( "textOpacity" ), d->opacity );
672 #ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
673  if ( d->textFont.stretch() > 0 )
674  textStyleElem.setAttribute( QStringLiteral( "stretchFactor" ), d->textFont.stretch() );
675 #endif
676  textStyleElem.setAttribute( QStringLiteral( "textOrientation" ), QgsTextRendererUtils::encodeTextOrientation( d->orientation ) );
677  textStyleElem.setAttribute( QStringLiteral( "blendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) );
678  textStyleElem.setAttribute( QStringLiteral( "multilineHeight" ), d->multilineHeight );
679  textStyleElem.setAttribute( QStringLiteral( "allowHtml" ), d->allowHtmlFormatting ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
680  textStyleElem.setAttribute( QStringLiteral( "capitalization" ), QString::number( static_cast< int >( d->capitalization ) ) );
681 
682  QDomElement ddElem = doc.createElement( QStringLiteral( "dd_properties" ) );
683  d->mDataDefinedProperties.writeXml( ddElem, QgsPalLayerSettings::propertyDefinitions() );
684 
685  textStyleElem.appendChild( mBufferSettings.writeXml( doc ) );
686  textStyleElem.appendChild( mMaskSettings.writeXml( doc ) );
687  textStyleElem.appendChild( mBackgroundSettings.writeXml( doc, context ) );
688  textStyleElem.appendChild( mShadowSettings.writeXml( doc ) );
689  textStyleElem.appendChild( ddElem );
690 
691  return textStyleElem;
692 }
693 
694 QMimeData *QgsTextFormat::toMimeData() const
695 {
696  //set both the mime color data, and the text (format settings).
697 
698  QMimeData *mimeData = new QMimeData;
699  mimeData->setColorData( QVariant( color() ) );
700 
701  QgsReadWriteContext rwContext;
702  QDomDocument textDoc;
703  QDomElement textElem = writeXml( textDoc, rwContext );
704  textDoc.appendChild( textElem );
705  mimeData->setText( textDoc.toString() );
706 
707  return mimeData;
708 }
709 
711 {
712  QgsTextFormat format;
713  format.setFont( font );
714  if ( font.pointSizeF() > 0 )
715  {
716  format.setSize( font.pointSizeF() );
718  }
719  else if ( font.pixelSize() > 0 )
720  {
721  format.setSize( font.pixelSize() );
723  }
724 
725  return format;
726 }
727 
729 {
730  QFont f = font();
731  switch ( sizeUnit() )
732  {
734  f.setPointSizeF( size() );
735  break;
736 
738  f.setPointSizeF( size() * 2.83464567 );
739  break;
740 
742  f.setPointSizeF( size() * 72 );
743  break;
744 
746  f.setPixelSize( static_cast< int >( std::round( size() ) ) );
747  break;
748 
753  // no meaning here
754  break;
755  }
756  return f;
757 }
758 
759 QgsTextFormat QgsTextFormat::fromMimeData( const QMimeData *data, bool *ok )
760 {
761  if ( ok )
762  *ok = false;
763  QgsTextFormat format;
764  if ( !data )
765  return format;
766 
767  QString text = data->text();
768  if ( !text.isEmpty() )
769  {
770  QDomDocument doc;
771  QDomElement elem;
772  QgsReadWriteContext rwContext;
773 
774  if ( doc.setContent( text ) )
775  {
776  elem = doc.documentElement();
777 
778  format.readXml( elem, rwContext );
779  if ( ok )
780  *ok = true;
781  return format;
782  }
783  }
784  return format;
785 }
786 
788 {
789  if ( d->blendMode != QPainter::CompositionMode_SourceOver )
790  return true;
791 
792  if ( mBufferSettings.enabled() && mBufferSettings.blendMode() != QPainter::CompositionMode_SourceOver )
793  return true;
794 
795  if ( mBackgroundSettings.enabled() && mBackgroundSettings.blendMode() != QPainter::CompositionMode_SourceOver )
796  return true;
797 
798  if ( mShadowSettings.enabled() && mShadowSettings.blendMode() != QPainter::CompositionMode_SourceOver )
799  return true;
800 
801  return false;
802 }
803 
805 {
806  d->isValid = true;
807  return d->mDataDefinedProperties;
808 }
809 
811 {
812  return d->mDataDefinedProperties;
813 }
814 
815 QSet<QString> QgsTextFormat::referencedFields( const QgsRenderContext &context ) const
816 {
817  QSet< QString > fields = d->mDataDefinedProperties.referencedFields( context.expressionContext(), true );
818  fields.unite( mBufferSettings.referencedFields( context ) );
819  fields.unite( mBackgroundSettings.referencedFields( context ) );
820  fields.unite( mShadowSettings.referencedFields( context ) );
821  fields.unite( mMaskSettings.referencedFields( context ) );
822  return fields;
823 }
824 
826 {
827  d->isValid = true;
828  d->mDataDefinedProperties = collection;
829 }
830 
832 {
833  d->isValid = true;
834  if ( !d->mDataDefinedProperties.hasActiveProperties() )
835  return;
836 
837  QString ddFontFamily;
838  context.expressionContext().setOriginalValueVariable( d->textFont.family() );
839  QVariant exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::Family, context.expressionContext() );
840  if ( !exprVal.isNull() )
841  {
842  QString family = exprVal.toString().trimmed();
843  if ( d->textFont.family() != family )
844  {
845  // testing for ddFontFamily in QFontDatabase.families() may be slow to do for every feature
846  // (i.e. don't use QgsFontUtils::fontFamilyMatchOnSystem( family ) here)
847  if ( QgsFontUtils::fontFamilyOnSystem( family ) )
848  {
849  ddFontFamily = family;
850  }
851  }
852  }
853 
854  // data defined named font style?
855  QString ddFontStyle;
856  context.expressionContext().setOriginalValueVariable( d->textNamedStyle );
857  exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontStyle, context.expressionContext() );
858  if ( !exprVal.isNull() )
859  {
860  QString fontstyle = exprVal.toString().trimmed();
861  ddFontStyle = fontstyle;
862  }
863 
864  bool ddBold = false;
865  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Bold ) )
866  {
867  context.expressionContext().setOriginalValueVariable( d->textFont.bold() );
868  ddBold = d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Bold, context.expressionContext(), false ) ;
869  }
870 
871  bool ddItalic = false;
872  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Italic ) )
873  {
874  context.expressionContext().setOriginalValueVariable( d->textFont.italic() );
875  ddItalic = d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Italic, context.expressionContext(), false );
876  }
877 
878  // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
879  // (currently defaults to what has been read in from layer settings)
880  QFont newFont;
881  QFontDatabase fontDb;
882  QFont appFont = QApplication::font();
883  bool newFontBuilt = false;
884  if ( ddBold || ddItalic )
885  {
886  // new font needs built, since existing style needs removed
887  newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : d->textFont.family() );
888  newFontBuilt = true;
889  newFont.setBold( ddBold );
890  newFont.setItalic( ddItalic );
891  }
892  else if ( !ddFontStyle.isEmpty()
893  && ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
894  {
895  if ( !ddFontFamily.isEmpty() )
896  {
897  // both family and style are different, build font from database
898  QFont styledfont = fontDb.font( ddFontFamily, ddFontStyle, appFont.pointSize() );
899  if ( appFont != styledfont )
900  {
901  newFont = styledfont;
902  newFontBuilt = true;
903  }
904  }
905 
906  // update the font face style
907  QgsFontUtils::updateFontViaStyle( newFontBuilt ? newFont : d->textFont, ddFontStyle );
908  }
909  else if ( !ddFontFamily.isEmpty() )
910  {
911  if ( ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
912  {
913  // just family is different, build font from database
914  QFont styledfont = fontDb.font( ddFontFamily, d->textNamedStyle, appFont.pointSize() );
915  if ( appFont != styledfont )
916  {
917  newFont = styledfont;
918  newFontBuilt = true;
919  }
920  }
921  else
922  {
923  newFont = QFont( ddFontFamily );
924  newFontBuilt = true;
925  }
926  }
927 
928  if ( newFontBuilt )
929  {
930  // copy over existing font settings
931  newFont.setUnderline( d->textFont.underline() );
932  newFont.setStrikeOut( d->textFont.strikeOut() );
933  newFont.setWordSpacing( d->textFont.wordSpacing() );
934  newFont.setLetterSpacing( QFont::AbsoluteSpacing, d->textFont.letterSpacing() );
935  d->textFont = newFont;
936  }
937 
938  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Underline ) )
939  {
940  context.expressionContext().setOriginalValueVariable( d->textFont.underline() );
941  d->textFont.setUnderline( d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Underline, context.expressionContext(), d->textFont.underline() ) );
942  }
943 
944  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Strikeout ) )
945  {
946  context.expressionContext().setOriginalValueVariable( d->textFont.strikeOut() );
947  d->textFont.setStrikeOut( d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Strikeout, context.expressionContext(), d->textFont.strikeOut() ) );
948  }
949 
950  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Color ) )
951  {
953  d->textColor = d->mDataDefinedProperties.valueAsColor( QgsPalLayerSettings::Color, context.expressionContext(), d->textColor );
954  }
955 
956  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Size ) )
957  {
959  d->fontSize = d->mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::Size, context.expressionContext(), d->fontSize );
960  }
961 
962  exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontSizeUnit, context.expressionContext() );
963  if ( !exprVal.isNull() )
964  {
965  QString units = exprVal.toString();
966  if ( !units.isEmpty() )
967  {
968  bool ok;
970  if ( ok )
971  d->fontSizeUnits = res;
972  }
973  }
974 
975  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontOpacity ) )
976  {
977  context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
978  const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontOpacity, context.expressionContext(), d->opacity * 100 );
979  if ( !val.isNull() )
980  {
981  d->opacity = val.toDouble() / 100.0;
982  }
983  }
984 
985 #ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
986  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontStretchFactor ) )
987  {
988  context.expressionContext().setOriginalValueVariable( d->textFont.stretch() );
989  const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontStretchFactor, context.expressionContext(), d->textFont.stretch() );
990  if ( !val.isNull() )
991  {
992  d->textFont.setStretch( val.toInt() );
993  }
994  }
995 #endif
996 
997  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::TextOrientation ) )
998  {
999  const QString encoded = QgsTextRendererUtils::encodeTextOrientation( d->orientation );
1000  context.expressionContext().setOriginalValueVariable( encoded );
1001  d->orientation = QgsTextRendererUtils::decodeTextOrientation( d->mDataDefinedProperties.value( QgsPalLayerSettings::TextOrientation, context.expressionContext(), encoded ).toString() );
1002  }
1003 
1004  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontLetterSpacing ) )
1005  {
1006  context.expressionContext().setOriginalValueVariable( d->textFont.letterSpacing() );
1007  const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontLetterSpacing, context.expressionContext(), d->textFont.letterSpacing() );
1008  if ( !val.isNull() )
1009  {
1010  d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, val.toDouble() );
1011  }
1012  }
1013 
1014  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontWordSpacing ) )
1015  {
1016  context.expressionContext().setOriginalValueVariable( d->textFont.wordSpacing() );
1017  const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontWordSpacing, context.expressionContext(), d->textFont.wordSpacing() );
1018  if ( !val.isNull() )
1019  {
1020  d->textFont.setWordSpacing( val.toDouble() );
1021  }
1022  }
1023 
1024  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontBlendMode ) )
1025  {
1026  exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontBlendMode, context.expressionContext() );
1027  QString blendstr = exprVal.toString().trimmed();
1028  if ( !blendstr.isEmpty() )
1029  d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
1030  }
1031 
1032  mShadowSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1033  mBackgroundSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1034  mBufferSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1035  mMaskSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1036 }
1037 
1038 QPixmap QgsTextFormat::textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText, int padding )
1039 {
1040  QgsTextFormat tempFormat = format;
1041  QPixmap pixmap( size );
1042  pixmap.fill( Qt::transparent );
1043  QPainter painter;
1044  painter.begin( &pixmap );
1045 
1046  painter.setRenderHint( QPainter::Antialiasing );
1047 
1048  QRect rect( 0, 0, size.width(), size.height() );
1049 
1050  // shameless eye candy - use a subtle gradient when drawing background
1051  painter.setPen( Qt::NoPen );
1052  QColor background1 = tempFormat.previewBackgroundColor();
1053  if ( ( background1.lightnessF() < 0.7 ) )
1054  {
1055  background1 = background1.darker( 125 );
1056  }
1057  else
1058  {
1059  background1 = background1.lighter( 125 );
1060  }
1061  QColor background2 = tempFormat.previewBackgroundColor();
1062  QLinearGradient linearGrad( QPointF( 0, 0 ), QPointF( 0, rect.height() ) );
1063  linearGrad.setColorAt( 0, background1 );
1064  linearGrad.setColorAt( 1, background2 );
1065  painter.setBrush( QBrush( linearGrad ) );
1066  if ( size.width() > 30 )
1067  {
1068  painter.drawRoundedRect( rect, 6, 6 );
1069  }
1070  else
1071  {
1072  // don't use rounded rect for small previews
1073  painter.drawRect( rect );
1074  }
1075  painter.setBrush( Qt::NoBrush );
1076  painter.setPen( Qt::NoPen );
1077  padding += 1; // move text away from background border
1078 
1079  QgsRenderContext context;
1080  QgsMapToPixel newCoordXForm;
1081  newCoordXForm.setParameters( 1, 0, 0, 0, 0, 0 );
1082  context.setMapToPixel( newCoordXForm );
1083 
1084 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1085  const double logicalDpiX = QgsApplication::desktop()->logicalDpiX();
1086 #else
1087  QWidget *activeWindow = QApplication::activeWindow();
1088  const double logicalDpiX = activeWindow && activeWindow->screen() ? activeWindow->screen()->logicalDotsPerInchX() : 96.0;
1089 #endif
1090  context.setScaleFactor( logicalDpiX / 25.4 );
1091 
1092  context.setUseAdvancedEffects( true );
1094  context.setPainter( &painter );
1096 
1097  // slightly inset text to account for buffer/background
1098  const double fontSize = context.convertToPainterUnits( tempFormat.size(), tempFormat.sizeUnit(), tempFormat.sizeMapUnitScale() );
1099  double xtrans = 0;
1100  if ( tempFormat.buffer().enabled() )
1101  xtrans = tempFormat.buffer().sizeUnit() == QgsUnitTypes::RenderPercentage
1102  ? fontSize * tempFormat.buffer().size() / 100
1103  : context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() );
1104  if ( tempFormat.background().enabled() && tempFormat.background().sizeType() != QgsTextBackgroundSettings::SizeFixed )
1105  xtrans = std::max( xtrans, context.convertToPainterUnits( tempFormat.background().size().width(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
1106 
1107  double ytrans = 0.0;
1108  if ( tempFormat.buffer().enabled() )
1109  ytrans = std::max( ytrans, tempFormat.buffer().sizeUnit() == QgsUnitTypes::RenderPercentage
1110  ? fontSize * tempFormat.buffer().size() / 100
1111  : context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() ) );
1112  if ( tempFormat.background().enabled() )
1113  ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat.background().size().height(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
1114 
1115  const QStringList text = QStringList() << ( previewText.isEmpty() ? QObject::tr( "Aa" ) : previewText );
1116  const double textHeight = QgsTextRenderer::textHeight( context, tempFormat, text, QgsTextRenderer::Rect );
1117  QRectF textRect = rect;
1118  textRect.setLeft( xtrans + padding );
1119  textRect.setWidth( rect.width() - xtrans - 2 * padding );
1120 
1121  if ( textRect.width() > 2000 )
1122  textRect.setWidth( 2000 - 2 * padding );
1123 
1124  const double bottom = textRect.height() / 2 + textHeight / 2;
1125  textRect.setTop( bottom - textHeight );
1126  textRect.setBottom( bottom );
1127 
1128  QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::AlignCenter, text, context, tempFormat );
1129 
1130  // draw border on top of text
1131  painter.setBrush( Qt::NoBrush );
1132  painter.setPen( QPen( tempFormat.previewBackgroundColor().darker( 150 ), 0 ) );
1133  if ( size.width() > 30 )
1134  {
1135  painter.drawRoundedRect( rect, 6, 6 );
1136  }
1137  else
1138  {
1139  // don't use rounded rect for small previews
1140  painter.drawRect( rect );
1141  }
1142  painter.end();
1143  return pixmap;
1144 }
Capitalization
String capitalization options.
Definition: qgis.h:1236
@ AllSmallCaps
Force all characters to small caps (since QGIS 3.24)
@ MixedCase
Mixed case, ie no change.
@ SmallCaps
Mixed case small caps (since QGIS 3.24)
@ Antialiasing
Use antialiasing while drawing.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
static QString translateNamedStyle(const QString &namedStyle)
Returns the localized named style of a font, if such a translation is available.
static QString untranslateNamedStyle(const QString &namedStyle)
Returns the english named style of a font, if possible.
static bool fontFamilyMatchOnSystem(const QString &family, QString *chosen=nullptr, bool *match=nullptr)
Check whether font family is on system.
static bool fontFamilyOnSystem(const QString &family)
Check whether font family is on system in a quick manner, which does not compare [foundry].
static bool updateFontViaStyle(QFont &f, const QString &fontstyle, bool fallback=false)
Updates font with named style and retain all font properties.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
void setParameters(double mapUnitsPerPixel, double centerX, double centerY, int widthPixels, int heightPixels, double rotation)
Sets parameters for use in transforming coordinates.
Struct for storing maximum and minimum scales for measurements in map units.
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
@ Strikeout
Use strikeout.
@ FontStyle
Font style name.
@ Underline
Use underline.
@ FontLetterSpacing
Letter spacing.
@ Bold
Use bold style.
@ FontStretchFactor
Font stretch factor, since QGIS 3.24.
@ FontSizeUnit
Font size units.
@ Italic
Use italic style.
@ FontWordSpacing
Word spacing.
@ FontBlendMode
Text blend mode.
@ Family
Font family.
@ FontOpacity
Text opacity.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the labeling property definitions.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
The class is used as a container of context for various read/write operations on other objects.
void pushMessage(const QString &message, Qgis::MessageLevel level=Qgis::MessageLevel::Warning) const
Append a message to the context.
Contains information about the context of a rendering operation.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
void setUseAdvancedEffects(bool enabled)
Used to enable or disable advanced effects such as blend modes.
QgsExpressionContext & expressionContext()
Gets the expression context.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
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 background object.
QSizeF size() const
Returns the size of the background shape.
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
void upgradeDataDefinedProperties(QgsPropertyCollection &properties)
Upgrade data defined properties when reading a project file saved in QGIS prior to version 3....
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the background shape.
bool enabled() const
Returns whether the background is enabled.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
void updateDataDefinedProperties(QgsRenderContext &context, const QgsPropertyCollection &properties)
Updates the format by evaluating current values of data defined properties.
SizeType sizeType() const
Returns the method used to determine the size of the background shape (e.g., fixed size or buffer aro...
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
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.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units used for the shape's size.
Container for settings relating to a text 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.
double size() const
Returns the size of the buffer.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
bool enabled() const
Returns whether the buffer is enabled.
QDomElement writeXml(QDomDocument &doc) const
Write settings into a DOM element.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
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 readXml(const QDomElement &elem)
Read settings from a DOM element.
Container for all settings relating to text rendering.
Definition: qgstextformat.h:41
QgsTextFormat()
Default constructor for QgsTextFormat.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the text.
void setSize(double size)
Sets the size for rendered text.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the size.
void setCapitalization(Qgis::Capitalization capitalization)
Sets the text capitalization style.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the format's property collection, used for data defined overrides.
QStringList families() const
Returns the list of font families to use when restoring the text format, in order of precedence.
void setFont(const QFont &font)
Sets the font used for rendering text.
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
void setFamilies(const QStringList &families)
Sets a list of font families to use for the text format, in order of precedence.
static QgsTextFormat fromMimeData(const QMimeData *data, bool *ok=nullptr)
Attempts to parse the provided mime data as a QgsTextFormat.
double lineHeight() const
Returns the line height for text.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
int stretchFactor() const
Returns the text's stretch factor.
void setOrientation(TextOrientation orientation)
Sets the orientation for the text.
void updateDataDefinedProperties(QgsRenderContext &context)
Updates the format by evaluating current values of data defined properties.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the format's property collection, used for data defined overrides.
void setStretchFactor(int factor)
Sets the text's stretch factor.
void setShadow(const QgsTextShadowSettings &shadowSettings)
Sets the text's drop shadow settings.
void setMask(const QgsTextMaskSettings &maskSettings)
Sets the text's masking settings.
void setPreviewBackgroundColor(const QColor &color)
Sets the background color that text will be rendered on for previews.
QFont scaledFont(const QgsRenderContext &context, double scaleFactor=1.0, bool *isZeroSize=nullptr) const
Returns a font with the size scaled to match the format's size settings (including units and map unit...
void setOpacity(double opacity)
Sets the text's opacity.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the text.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
bool operator==(const QgsTextFormat &other) const
TextOrientation orientation() const
Returns the orientation of the text.
void setAllowHtmlFormatting(bool allow)
Sets whether text should be treated as a HTML document and HTML tags should be used for formatting th...
Qgis::Capitalization capitalization() const
Returns the text capitalization style.
QgsTextMaskSettings & mask()
Returns a reference to the masking settings.
static QPixmap textFormatPreviewPixmap(const QgsTextFormat &format, QSize size, const QString &previewText=QString(), int padding=0)
Returns a pixmap preview for a text format.
bool isValid() const
Returns true if the format is valid.
void setBuffer(const QgsTextBufferSettings &bufferSettings)
Sets the text's buffer settings.
QgsTextBackgroundSettings & background()
Returns a reference to the text background settings.
TextOrientation
Text orientation.
Definition: qgstextformat.h:46
static QgsTextFormat fromQFont(const QFont &font)
Returns a text format matching the settings from an input font.
void setValid()
Sets the format to a valid state, without changing any of the default format settings.
bool allowHtmlFormatting() const
Returns true if text should be treated as a HTML document and HTML tags should be used for formatting...
QFont toQFont() const
Returns a QFont matching the relevant settings from this text format.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
bool operator!=(const QgsTextFormat &other) const
double opacity() const
Returns the text's opacity.
QString namedStyle() const
Returns the named style for the font used for rendering text (e.g., "bold").
double size() const
Returns the size for rendered text.
QgsTextShadowSettings & shadow()
Returns a reference to the text drop shadow settings.
QgsTextFormat & operator=(const QgsTextFormat &other)
void setBackground(const QgsTextBackgroundSettings &backgroundSettings)
Sets the text's background settings.q.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
QMimeData * toMimeData() const
Returns new mime data representing the text format settings.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the size.
void setNamedStyle(const QString &style)
Sets the named style for the font used for rendering text.
QColor color() const
Returns the color that text will be rendered in.
QFont font() const
Returns the font used for rendering text.
void readFromLayer(QgsVectorLayer *layer)
Reads settings from a layer's custom properties (for QGIS 2.x projects).
QColor previewBackgroundColor() const
Returns the background color for text previews.
bool containsAdvancedEffects() const
Returns true if any component of the font format requires advanced effects such as blend modes,...
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
void setLineHeight(double height)
Sets the line height for text.
Container for settings relating to a selective masking around a text.
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
void updateDataDefinedProperties(QgsRenderContext &context, const QgsPropertyCollection &properties)
Updates the format by evaluating current values of data defined properties.
void readXml(const QDomElement &elem)
Read settings from a DOM element.
QDomElement writeXml(QDomDocument &doc) const
Write settings into a DOM element.
static QString encodeTextOrientation(QgsTextFormat::TextOrientation orientation)
Encodes a text orientation.
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 QgsTextFormat::TextOrientation decodeTextOrientation(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of a text orientation.
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, VAlignment vAlignment=AlignTop, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags())
Draws text within a rectangle using the specified settings.
@ AlignCenter
Center align.
static int sizeToPixel(double size, const QgsRenderContext &c, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale())
Calculates pixel size (considering output size should be in pixel or map units, scale factors and opt...
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode=Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
@ Rect
Text within rectangle draw mode.
Container for settings relating to a text shadow.
bool enabled() const
Returns whether the shadow is enabled.
void readXml(const QDomElement &elem)
Read settings from a DOM element.
QDomElement writeXml(QDomDocument &doc) const
Write settings into a DOM element.
void updateDataDefinedProperties(QgsRenderContext &context, const QgsPropertyCollection &properties)
Updates the format by evaluating current values of data defined properties.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the drop shadow.
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
void readFromLayer(QgsVectorLayer *layer)
Reads settings from a layer's custom properties (for QGIS 2.x projects).
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
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:175
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:176
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
Definition: qgsunittypes.h:172
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:173
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:171
@ RenderInches
Inches.
Definition: qgsunittypes.h:174
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
Represents a vector layer which manages a vector based data sets.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578