QGIS API Documentation  3.27.0-Master (0e23467727)
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 "qgsfontmanager.h"
27 
28 #include <QFontDatabase>
29 #include <QMimeData>
30 #include <QWidget>
31 #include <QScreen>
32 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
33 #include <QDesktopWidget>
34 #endif
35 
37 {
38  d = new QgsTextSettingsPrivate();
39 }
40 
42  : mBufferSettings( other.mBufferSettings )
43  , mBackgroundSettings( other.mBackgroundSettings )
44  , mShadowSettings( other.mShadowSettings )
45  , mMaskSettings( other.mMaskSettings )
46  , mTextFontFamily( other.mTextFontFamily )
47  , mTextFontFound( other.mTextFontFound )
48  , d( other.d )
49 {
50 
51 }
52 
54 {
55  d = other.d;
56  mBufferSettings = other.mBufferSettings;
57  mBackgroundSettings = other.mBackgroundSettings;
58  mShadowSettings = other.mShadowSettings;
59  mMaskSettings = other.mMaskSettings;
60  mTextFontFamily = other.mTextFontFamily;
61  mTextFontFound = other.mTextFontFound;
62  return *this;
63 }
64 
66 {
67 
68 }
69 
70 bool QgsTextFormat::operator==( const QgsTextFormat &other ) const
71 {
72  if ( d->isValid != other.isValid()
73  || d->textFont != other.font()
74  || namedStyle() != other.namedStyle()
75  || d->fontSizeUnits != other.sizeUnit()
76  || d->fontSizeMapUnitScale != other.sizeMapUnitScale()
77  || d->fontSize != other.size()
78  || d->textColor != other.color()
79  || d->opacity != other.opacity()
80  || d->blendMode != other.blendMode()
81  || d->multilineHeight != other.lineHeight()
82  || d->orientation != other.orientation()
83  || d->previewBackgroundColor != other.previewBackgroundColor()
84  || d->allowHtmlFormatting != other.allowHtmlFormatting()
85  || d->forcedBold != other.forcedBold()
86  || d->forcedItalic != other.forcedItalic()
87  || d->capitalization != other.capitalization()
88  || mBufferSettings != other.mBufferSettings
89  || mBackgroundSettings != other.mBackgroundSettings
90  || mShadowSettings != other.mShadowSettings
91  || mMaskSettings != other.mMaskSettings
92  || d->families != other.families()
93  || d->mDataDefinedProperties != other.dataDefinedProperties() )
94  return false;
95 
96  return true;
97 }
98 
99 bool QgsTextFormat::operator!=( const QgsTextFormat &other ) const
100 {
101  return !( *this == other );
102 }
103 
105 {
106  return d->isValid;
107 }
108 
110 {
111  d->isValid = true;
112 }
113 
115 {
116  d->isValid = true;
117  return mBufferSettings;
118 }
119 
120 void QgsTextFormat::setBuffer( const QgsTextBufferSettings &bufferSettings )
121 {
122  d->isValid = true;
123  mBufferSettings = bufferSettings;
124 }
125 
127 {
128  d->isValid = true;
129  return mBackgroundSettings;
130 }
131 
133 {
134  d->isValid = true;
135  mBackgroundSettings = backgroundSettings;
136 }
137 
139 {
140  d->isValid = true;
141  return mShadowSettings;
142 }
143 
144 void QgsTextFormat::setShadow( const QgsTextShadowSettings &shadowSettings )
145 {
146  d->isValid = true;
147  mShadowSettings = shadowSettings;
148 }
149 
151 {
152  d->isValid = true;
153  return mMaskSettings;
154 }
155 
156 void QgsTextFormat::setMask( const QgsTextMaskSettings &maskSettings )
157 {
158  d->isValid = true;
159  mMaskSettings = maskSettings;
160 }
161 
162 QFont QgsTextFormat::font() const
163 {
164  return d->textFont;
165 }
166 
167 QFont QgsTextFormat::scaledFont( const QgsRenderContext &context, double scaleFactor, bool *isZeroSize ) const
168 {
169  if ( isZeroSize )
170  *isZeroSize = false;
171 
172  QFont font = d->textFont;
173  if ( scaleFactor == 1 )
174  {
175  int fontPixelSize = QgsTextRenderer::sizeToPixel( d->fontSize, context, d->fontSizeUnits,
176  d->fontSizeMapUnitScale );
177  if ( fontPixelSize == 0 )
178  {
179  if ( isZeroSize )
180  *isZeroSize = true;
181  return QFont();
182  }
183 
184  font.setPixelSize( fontPixelSize );
185  }
186  else
187  {
188  double fontPixelSize = context.convertToPainterUnits( d->fontSize, d->fontSizeUnits, d->fontSizeMapUnitScale );
189  if ( qgsDoubleNear( fontPixelSize, 0 ) )
190  {
191  if ( isZeroSize )
192  *isZeroSize = true;
193  return QFont();
194  }
195  const int roundedPixelSize = static_cast< int >( std::round( scaleFactor * fontPixelSize + 0.5 ) );
196  font.setPixelSize( roundedPixelSize );
197  }
198 
199  font.setLetterSpacing( QFont::AbsoluteSpacing, context.convertToPainterUnits( d->textFont.letterSpacing(), d->fontSizeUnits, d->fontSizeMapUnitScale ) * scaleFactor );
200  font.setWordSpacing( context.convertToPainterUnits( d->textFont.wordSpacing(), d->fontSizeUnits, d->fontSizeMapUnitScale ) * scaleFactor * scaleFactor );
201 
202  if ( d->capitalization == Qgis::Capitalization::SmallCaps
203  || d->capitalization == Qgis::Capitalization::AllSmallCaps )
204  font.setCapitalization( QFont::SmallCaps );
205 
206  return font;
207 }
208 
209 void QgsTextFormat::setFont( const QFont &font )
210 {
211  d->isValid = true;
212  d->textFont = font;
213 }
214 
216 {
217  if ( !d->textNamedStyle.isEmpty() )
218  return d->textNamedStyle;
219 
220  QFontDatabase db;
221  return db.styleString( d->textFont );
222 }
223 
224 void QgsTextFormat::setNamedStyle( const QString &style )
225 {
226  d->isValid = true;
227  QgsFontUtils::updateFontViaStyle( d->textFont, style );
228  d->textNamedStyle = style;
229 }
230 
232 {
233  return d->forcedBold;
234 }
235 
236 void QgsTextFormat::setForcedBold( bool forced )
237 {
238  d->isValid = true;
239  d->textFont.setBold( forced );
240  d->forcedBold = true;
241 }
242 
244 {
245  return d->forcedItalic;
246 }
247 
249 {
250  d->isValid = true;
251  d->textFont.setItalic( forced );
252  d->forcedItalic = true;
253 }
254 
255 QStringList QgsTextFormat::families() const
256 {
257  return d->families;
258 }
259 
260 void QgsTextFormat::setFamilies( const QStringList &families )
261 {
262  d->isValid = true;
263  d->families = families;
264 }
265 
267 {
268  return d->fontSizeUnits;
269 }
270 
272 {
273  d->isValid = true;
274  d->fontSizeUnits = unit;
275 }
276 
278 {
279  return d->fontSizeMapUnitScale;
280 }
281 
283 {
284  d->isValid = true;
285  d->fontSizeMapUnitScale = scale;
286 }
287 
288 double QgsTextFormat::size() const
289 {
290  return d->fontSize;
291 }
292 
293 void QgsTextFormat::setSize( double size )
294 {
295  d->isValid = true;
296  d->fontSize = size;
297 }
298 
299 QColor QgsTextFormat::color() const
300 {
301  return d->textColor;
302 }
303 
304 void QgsTextFormat::setColor( const QColor &color )
305 {
306  d->isValid = true;
307  d->textColor = color;
308 }
309 
311 {
312  return d->opacity;
313 }
314 
315 void QgsTextFormat::setOpacity( double opacity )
316 {
317  d->isValid = true;
318  d->opacity = opacity;
319 }
320 
322 {
323  return d->textFont.stretch() > 0 ? d->textFont.stretch() : 100;
324 }
325 
327 {
328  d->isValid = true;
329  d->textFont.setStretch( factor );
330 }
331 
332 QPainter::CompositionMode QgsTextFormat::blendMode() const
333 {
334  return d->blendMode;
335 }
336 
337 void QgsTextFormat::setBlendMode( QPainter::CompositionMode mode )
338 {
339  d->isValid = true;
340  d->blendMode = mode;
341 }
342 
344 {
345  return d->multilineHeight;
346 }
347 
348 void QgsTextFormat::setLineHeight( double height )
349 {
350  d->isValid = true;
351  d->multilineHeight = height;
352 }
353 
355 {
356  return d->orientation;
357 }
358 
360 {
361  d->isValid = true;
362  d->orientation = orientation;
363 }
364 
366 {
367  // bit of complexity here to maintain API..
368  return d->capitalization == Qgis::Capitalization::MixedCase && d->textFont.capitalization() != QFont::MixedCase
369  ? static_cast< Qgis::Capitalization >( d->textFont.capitalization() )
370  : d->capitalization ;
371 }
372 
374 {
375  d->isValid = true;
376  d->capitalization = capitalization;
377 #if defined(HAS_KDE_QT5_SMALL_CAPS_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
378  d->textFont.setCapitalization( capitalization == Qgis::Capitalization::SmallCaps || capitalization == Qgis::Capitalization::AllSmallCaps ? QFont::SmallCaps : QFont::MixedCase );
379 #else
380  d->textFont.setCapitalization( QFont::MixedCase );
381 #endif
382 }
383 
385 {
386  return d->allowHtmlFormatting;
387 }
388 
390 {
391  d->isValid = true;
392  d->allowHtmlFormatting = allow;
393 }
394 
396 {
397  return d->previewBackgroundColor;
398 }
399 
400 void QgsTextFormat::setPreviewBackgroundColor( const QColor &color )
401 {
402  d->isValid = true;
403  d->previewBackgroundColor = color;
404 }
405 
407 {
408  d->isValid = true;
409  QFont appFont = QApplication::font();
410  mTextFontFamily = QgsApplication::fontManager()->processFontFamilyName( layer->customProperty( QStringLiteral( "labeling/fontFamily" ), QVariant( appFont.family() ) ).toString() );
411  QString fontFamily = mTextFontFamily;
412  if ( mTextFontFamily != appFont.family() && !QgsFontUtils::fontFamilyMatchOnSystem( mTextFontFamily ) )
413  {
414  // trigger to notify about font family substitution
415  mTextFontFound = false;
416 
417  // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
418  // currently only defaults to matching algorithm for resolving [foundry], if a font of similar family is found (default for QFont)
419 
420  // for now, do not use matching algorithm for substitution if family not found, substitute default instead
421  fontFamily = appFont.family();
422  }
423  else
424  {
425  mTextFontFound = true;
426  }
427 
428  if ( !layer->customProperty( QStringLiteral( "labeling/fontSize" ) ).isValid() )
429  {
430  d->fontSize = appFont.pointSizeF();
431  }
432  else
433  {
434  d->fontSize = layer->customProperty( QStringLiteral( "labeling/fontSize" ) ).toDouble();
435  }
436 
437  if ( layer->customProperty( QStringLiteral( "labeling/fontSizeUnit" ) ).toString().isEmpty() )
438  {
439  d->fontSizeUnits = layer->customProperty( QStringLiteral( "labeling/fontSizeInMapUnits" ), QVariant( false ) ).toBool() ?
441  }
442  else
443  {
444  bool ok = false;
445  d->fontSizeUnits = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/fontSizeUnit" ) ).toString(), &ok );
446  if ( !ok )
447  d->fontSizeUnits = QgsUnitTypes::RenderPoints;
448  }
449  if ( layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitScale" ) ).toString().isEmpty() )
450  {
451  //fallback to older property
452  double oldMin = layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitMinScale" ), 0.0 ).toDouble();
453  d->fontSizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
454  double oldMax = layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitMaxScale" ), 0.0 ).toDouble();
455  d->fontSizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
456  }
457  else
458  {
459  d->fontSizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitScale" ) ).toString() );
460  }
461  int fontWeight = layer->customProperty( QStringLiteral( "labeling/fontWeight" ) ).toInt();
462  bool fontItalic = layer->customProperty( QStringLiteral( "labeling/fontItalic" ) ).toBool();
463  d->textFont = QFont( fontFamily, d->fontSize, fontWeight, fontItalic );
464  d->textNamedStyle = QgsFontUtils::translateNamedStyle( layer->customProperty( QStringLiteral( "labeling/namedStyle" ), QVariant( "" ) ).toString() );
465  QgsFontUtils::updateFontViaStyle( d->textFont, d->textNamedStyle ); // must come after textFont.setPointSizeF()
466  d->capitalization = static_cast< Qgis::Capitalization >( layer->customProperty( QStringLiteral( "labeling/fontCapitals" ), QVariant( 0 ) ).toUInt() );
467  d->textFont.setUnderline( layer->customProperty( QStringLiteral( "labeling/fontUnderline" ) ).toBool() );
468  d->textFont.setStrikeOut( layer->customProperty( QStringLiteral( "labeling/fontStrikeout" ) ).toBool() );
469  d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, layer->customProperty( QStringLiteral( "labeling/fontLetterSpacing" ), QVariant( 0.0 ) ).toDouble() );
470  d->textFont.setWordSpacing( layer->customProperty( QStringLiteral( "labeling/fontWordSpacing" ), QVariant( 0.0 ) ).toDouble() );
471  d->textColor = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/textColor" ), Qt::black, false );
472  if ( layer->customProperty( QStringLiteral( "labeling/textOpacity" ) ).toString().isEmpty() )
473  {
474  d->opacity = ( 1 - layer->customProperty( QStringLiteral( "labeling/textTransp" ) ).toInt() / 100.0 ); //0 -100
475  }
476  else
477  {
478  d->opacity = ( layer->customProperty( QStringLiteral( "labeling/textOpacity" ) ).toDouble() );
479  }
480  d->blendMode = QgsPainting::getCompositionMode(
481  static_cast< QgsPainting::BlendMode >( layer->customProperty( QStringLiteral( "labeling/blendMode" ), QVariant( QgsPainting::BlendNormal ) ).toUInt() ) );
482  d->multilineHeight = layer->customProperty( QStringLiteral( "labeling/multilineHeight" ), QVariant( 1.0 ) ).toDouble();
483  d->previewBackgroundColor = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/previewBkgrdColor" ), QColor( 255, 255, 255 ), false );
484 
485  mBufferSettings.readFromLayer( layer );
486  mShadowSettings.readFromLayer( layer );
487  mBackgroundSettings.readFromLayer( layer );
488 }
489 
490 void QgsTextFormat::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
491 {
492  d->isValid = true;
493  QDomElement textStyleElem;
494  if ( elem.nodeName() == QLatin1String( "text-style" ) )
495  textStyleElem = elem;
496  else
497  textStyleElem = elem.firstChildElement( QStringLiteral( "text-style" ) );
498  QFont appFont = QApplication::font();
499  mTextFontFamily = QgsApplication::fontManager()->processFontFamilyName( textStyleElem.attribute( QStringLiteral( "fontFamily" ), appFont.family() ) );
500  QString fontFamily = mTextFontFamily;
501 
502  const QDomElement familiesElem = textStyleElem.firstChildElement( QStringLiteral( "families" ) );
503  const QDomNodeList familyNodes = familiesElem.childNodes();
504  QStringList families;
505  families.reserve( familyNodes.size() );
506  for ( int i = 0; i < familyNodes.count(); ++i )
507  {
508  const QDomElement familyElem = familyNodes.at( i ).toElement();
509  families << familyElem.attribute( QStringLiteral( "name" ) );
510  }
511  d->families = families;
512 
513  mTextFontFound = false;
514  QString matched;
515  if ( mTextFontFamily != appFont.family() && !QgsFontUtils::fontFamilyMatchOnSystem( mTextFontFamily ) )
516  {
517  if ( QgsApplication::fontManager()->tryToDownloadFontFamily( mTextFontFamily, matched ) )
518  {
519  mTextFontFound = true;
520  }
521  else
522  {
523  for ( const QString &family : std::as_const( families ) )
524  {
525  const QString processedFamily = QgsApplication::fontManager()->processFontFamilyName( family );
526  if ( QgsFontUtils::fontFamilyMatchOnSystem( processedFamily ) ||
527  QgsApplication::fontManager()->tryToDownloadFontFamily( processedFamily, matched ) )
528  {
529  mTextFontFound = true;
530  fontFamily = processedFamily;
531  break;
532  }
533  }
534 
535  if ( !mTextFontFound )
536  {
537  // couldn't even find a matching font in the backup list -- substitute default instead
538  fontFamily = appFont.family();
539  }
540  }
541  }
542  else
543  {
544  mTextFontFound = true;
545  }
546 
547  if ( !mTextFontFound )
548  {
549  context.pushMessage( QObject::tr( "Font “%1” not available on system" ).arg( mTextFontFamily ) );
550  }
551 
552  if ( textStyleElem.hasAttribute( QStringLiteral( "fontSize" ) ) )
553  {
554  d->fontSize = textStyleElem.attribute( QStringLiteral( "fontSize" ) ).toDouble();
555  }
556  else
557  {
558  d->fontSize = appFont.pointSizeF();
559  }
560 
561  if ( !textStyleElem.hasAttribute( QStringLiteral( "fontSizeUnit" ) ) )
562  {
563  d->fontSizeUnits = textStyleElem.attribute( QStringLiteral( "fontSizeInMapUnits" ) ).toUInt() == 0 ? QgsUnitTypes::RenderPoints
565  }
566  else
567  {
568  d->fontSizeUnits = QgsUnitTypes::decodeRenderUnit( textStyleElem.attribute( QStringLiteral( "fontSizeUnit" ) ) );
569  }
570 
571  if ( !textStyleElem.hasAttribute( QStringLiteral( "fontSizeMapUnitScale" ) ) )
572  {
573  //fallback to older property
574  double oldMin = textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
575  d->fontSizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
576  double oldMax = textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
577  d->fontSizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
578  }
579  else
580  {
581  d->fontSizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitScale" ) ) );
582  }
583  int fontWeight = textStyleElem.attribute( QStringLiteral( "fontWeight" ) ).toInt();
584  bool fontItalic = textStyleElem.attribute( QStringLiteral( "fontItalic" ) ).toInt();
585  d->textFont = QFont( fontFamily, d->fontSize, fontWeight, fontItalic );
586  d->textFont.setPointSizeF( d->fontSize ); //double precision needed because of map units
587  d->textNamedStyle = QgsFontUtils::translateNamedStyle( textStyleElem.attribute( QStringLiteral( "namedStyle" ) ) );
588  QgsFontUtils::updateFontViaStyle( d->textFont, d->textNamedStyle ); // must come after textFont.setPointSizeF()
589  d->forcedBold = textStyleElem.attribute( QStringLiteral( "forcedBold" ) ).toInt();
590  d->forcedItalic = textStyleElem.attribute( QStringLiteral( "forcedItalic" ) ).toInt();
591  d->textFont.setUnderline( textStyleElem.attribute( QStringLiteral( "fontUnderline" ) ).toInt() );
592  d->textFont.setStrikeOut( textStyleElem.attribute( QStringLiteral( "fontStrikeout" ) ).toInt() );
593  d->textFont.setKerning( textStyleElem.attribute( QStringLiteral( "fontKerning" ), QStringLiteral( "1" ) ).toInt() );
594  d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, textStyleElem.attribute( QStringLiteral( "fontLetterSpacing" ), QStringLiteral( "0" ) ).toDouble() );
595  d->textFont.setWordSpacing( textStyleElem.attribute( QStringLiteral( "fontWordSpacing" ), QStringLiteral( "0" ) ).toDouble() );
596  d->textColor = QgsSymbolLayerUtils::decodeColor( textStyleElem.attribute( QStringLiteral( "textColor" ), QgsSymbolLayerUtils::encodeColor( Qt::black ) ) );
597  if ( !textStyleElem.hasAttribute( QStringLiteral( "textOpacity" ) ) )
598  {
599  d->opacity = ( 1 - textStyleElem.attribute( QStringLiteral( "textTransp" ) ).toInt() / 100.0 ); //0 -100
600  }
601  else
602  {
603  d->opacity = ( textStyleElem.attribute( QStringLiteral( "textOpacity" ) ).toDouble() );
604  }
605 #ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
606  d->textFont.setStretch( textStyleElem.attribute( QStringLiteral( "stretchFactor" ), QStringLiteral( "100" ) ).toInt() );
607 #endif
608  d->orientation = QgsTextRendererUtils::decodeTextOrientation( textStyleElem.attribute( QStringLiteral( "textOrientation" ) ) );
609  d->previewBackgroundColor = QgsSymbolLayerUtils::decodeColor( textStyleElem.attribute( QStringLiteral( "previewBkgrdColor" ), QgsSymbolLayerUtils::encodeColor( Qt::white ) ) );
610 
611  d->blendMode = QgsPainting::getCompositionMode(
612  static_cast< QgsPainting::BlendMode >( textStyleElem.attribute( QStringLiteral( "blendMode" ), QString::number( QgsPainting::BlendNormal ) ).toUInt() ) );
613 
614  if ( !textStyleElem.hasAttribute( QStringLiteral( "multilineHeight" ) ) )
615  {
616  QDomElement textFormatElem = elem.firstChildElement( QStringLiteral( "text-format" ) );
617  d->multilineHeight = textFormatElem.attribute( QStringLiteral( "multilineHeight" ), QStringLiteral( "1" ) ).toDouble();
618  }
619  else
620  {
621  d->multilineHeight = textStyleElem.attribute( QStringLiteral( "multilineHeight" ), QStringLiteral( "1" ) ).toDouble();
622  }
623 
624  if ( textStyleElem.hasAttribute( QStringLiteral( "capitalization" ) ) )
625  d->capitalization = static_cast< Qgis::Capitalization >( textStyleElem.attribute( QStringLiteral( "capitalization" ), QString::number( static_cast< int >( Qgis::Capitalization::MixedCase ) ) ).toInt() );
626  else
627  d->capitalization = static_cast< Qgis::Capitalization >( textStyleElem.attribute( QStringLiteral( "fontCapitals" ), QStringLiteral( "0" ) ).toUInt() );
628 
629  if ( d->capitalization == Qgis::Capitalization::SmallCaps || d->capitalization == Qgis::Capitalization::AllSmallCaps )
630  d->textFont.setCapitalization( QFont::SmallCaps );
631 
632  d->allowHtmlFormatting = textStyleElem.attribute( QStringLiteral( "allowHtml" ), QStringLiteral( "0" ) ).toInt();
633 
634  if ( textStyleElem.firstChildElement( QStringLiteral( "text-buffer" ) ).isNull() )
635  {
636  mBufferSettings.readXml( elem );
637  }
638  else
639  {
640  mBufferSettings.readXml( textStyleElem );
641  }
642  if ( textStyleElem.firstChildElement( QStringLiteral( "text-mask" ) ).isNull() )
643  {
644  mMaskSettings.readXml( elem );
645  }
646  else
647  {
648  mMaskSettings.readXml( textStyleElem );
649  }
650  if ( textStyleElem.firstChildElement( QStringLiteral( "shadow" ) ).isNull() )
651  {
652  mShadowSettings.readXml( elem );
653  }
654  else
655  {
656  mShadowSettings.readXml( textStyleElem );
657  }
658  if ( textStyleElem.firstChildElement( QStringLiteral( "background" ) ).isNull() )
659  {
660  mBackgroundSettings.readXml( elem, context );
661  }
662  else
663  {
664  mBackgroundSettings.readXml( textStyleElem, context );
665  }
666 
667  QDomElement ddElem = textStyleElem.firstChildElement( QStringLiteral( "dd_properties" ) );
668  if ( ddElem.isNull() )
669  {
670  ddElem = elem.firstChildElement( QStringLiteral( "dd_properties" ) );
671  }
672  if ( !ddElem.isNull() )
673  {
674  d->mDataDefinedProperties.readXml( ddElem, QgsPalLayerSettings::propertyDefinitions() );
675  mBackgroundSettings.upgradeDataDefinedProperties( d->mDataDefinedProperties );
676  }
677  else
678  {
679  d->mDataDefinedProperties.clear();
680  }
681 }
682 
683 QDomElement QgsTextFormat::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
684 {
685  // text style
686  QDomElement textStyleElem = doc.createElement( QStringLiteral( "text-style" ) );
687  textStyleElem.setAttribute( QStringLiteral( "fontFamily" ), d->textFont.family() );
688 
689  QDomElement familiesElem = doc.createElement( QStringLiteral( "families" ) );
690  for ( const QString &family : std::as_const( d->families ) )
691  {
692  QDomElement familyElem = doc.createElement( QStringLiteral( "family" ) );
693  familyElem.setAttribute( QStringLiteral( "name" ), family );
694  familiesElem.appendChild( familyElem );
695  }
696  textStyleElem.appendChild( familiesElem );
697 
698  textStyleElem.setAttribute( QStringLiteral( "namedStyle" ), QgsFontUtils::untranslateNamedStyle( d->textNamedStyle ) );
699  textStyleElem.setAttribute( QStringLiteral( "fontSize" ), d->fontSize );
700  textStyleElem.setAttribute( QStringLiteral( "fontSizeUnit" ), QgsUnitTypes::encodeUnit( d->fontSizeUnits ) );
701  textStyleElem.setAttribute( QStringLiteral( "fontSizeMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->fontSizeMapUnitScale ) );
702  textStyleElem.setAttribute( QStringLiteral( "fontWeight" ), d->textFont.weight() );
703  textStyleElem.setAttribute( QStringLiteral( "fontItalic" ), d->textFont.italic() );
704  textStyleElem.setAttribute( QStringLiteral( "fontStrikeout" ), d->textFont.strikeOut() );
705  textStyleElem.setAttribute( QStringLiteral( "fontUnderline" ), d->textFont.underline() );
706  textStyleElem.setAttribute( QStringLiteral( "forcedBold" ), d->forcedBold );
707  textStyleElem.setAttribute( QStringLiteral( "forcedItalic" ), d->forcedItalic );
708  textStyleElem.setAttribute( QStringLiteral( "textColor" ), QgsSymbolLayerUtils::encodeColor( d->textColor ) );
709  textStyleElem.setAttribute( QStringLiteral( "previewBkgrdColor" ), QgsSymbolLayerUtils::encodeColor( d->previewBackgroundColor ) );
710  textStyleElem.setAttribute( QStringLiteral( "fontLetterSpacing" ), d->textFont.letterSpacing() );
711  textStyleElem.setAttribute( QStringLiteral( "fontWordSpacing" ), d->textFont.wordSpacing() );
712  textStyleElem.setAttribute( QStringLiteral( "fontKerning" ), d->textFont.kerning() );
713  textStyleElem.setAttribute( QStringLiteral( "textOpacity" ), d->opacity );
714 #ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
715  if ( d->textFont.stretch() > 0 )
716  textStyleElem.setAttribute( QStringLiteral( "stretchFactor" ), d->textFont.stretch() );
717 #endif
718  textStyleElem.setAttribute( QStringLiteral( "textOrientation" ), QgsTextRendererUtils::encodeTextOrientation( d->orientation ) );
719  textStyleElem.setAttribute( QStringLiteral( "blendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) );
720  textStyleElem.setAttribute( QStringLiteral( "multilineHeight" ), d->multilineHeight );
721  textStyleElem.setAttribute( QStringLiteral( "allowHtml" ), d->allowHtmlFormatting ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
722  textStyleElem.setAttribute( QStringLiteral( "capitalization" ), QString::number( static_cast< int >( d->capitalization ) ) );
723 
724  QDomElement ddElem = doc.createElement( QStringLiteral( "dd_properties" ) );
725  d->mDataDefinedProperties.writeXml( ddElem, QgsPalLayerSettings::propertyDefinitions() );
726 
727  textStyleElem.appendChild( mBufferSettings.writeXml( doc ) );
728  textStyleElem.appendChild( mMaskSettings.writeXml( doc ) );
729  textStyleElem.appendChild( mBackgroundSettings.writeXml( doc, context ) );
730  textStyleElem.appendChild( mShadowSettings.writeXml( doc ) );
731  textStyleElem.appendChild( ddElem );
732 
733  return textStyleElem;
734 }
735 
736 QMimeData *QgsTextFormat::toMimeData() const
737 {
738  //set both the mime color data, and the text (format settings).
739 
740  QMimeData *mimeData = new QMimeData;
741  mimeData->setColorData( QVariant( color() ) );
742 
743  QgsReadWriteContext rwContext;
744  QDomDocument textDoc;
745  QDomElement textElem = writeXml( textDoc, rwContext );
746  textDoc.appendChild( textElem );
747  mimeData->setText( textDoc.toString() );
748 
749  return mimeData;
750 }
751 
753 {
754  QgsTextFormat format;
755  format.setFont( font );
756  if ( font.pointSizeF() > 0 )
757  {
758  format.setSize( font.pointSizeF() );
760  }
761  else if ( font.pixelSize() > 0 )
762  {
763  format.setSize( font.pixelSize() );
765  }
766 
767  return format;
768 }
769 
771 {
772  QFont f = font();
773  switch ( sizeUnit() )
774  {
776  f.setPointSizeF( size() );
777  break;
778 
780  f.setPointSizeF( size() * 2.83464567 );
781  break;
782 
784  f.setPointSizeF( size() * 72 );
785  break;
786 
788  f.setPixelSize( static_cast< int >( std::round( size() ) ) );
789  break;
790 
795  // no meaning here
796  break;
797  }
798  return f;
799 }
800 
801 QgsTextFormat QgsTextFormat::fromMimeData( const QMimeData *data, bool *ok )
802 {
803  if ( ok )
804  *ok = false;
805  QgsTextFormat format;
806  if ( !data )
807  return format;
808 
809  QString text = data->text();
810  if ( !text.isEmpty() )
811  {
812  QDomDocument doc;
813  QDomElement elem;
814  QgsReadWriteContext rwContext;
815 
816  if ( doc.setContent( text ) )
817  {
818  elem = doc.documentElement();
819 
820  format.readXml( elem, rwContext );
821  if ( ok )
822  *ok = true;
823  return format;
824  }
825  }
826  return format;
827 }
828 
830 {
831  if ( d->blendMode != QPainter::CompositionMode_SourceOver )
832  return true;
833 
834  if ( mBufferSettings.enabled() && mBufferSettings.blendMode() != QPainter::CompositionMode_SourceOver )
835  return true;
836 
837  if ( mBackgroundSettings.enabled() && mBackgroundSettings.blendMode() != QPainter::CompositionMode_SourceOver )
838  return true;
839 
840  if ( mShadowSettings.enabled() && mShadowSettings.blendMode() != QPainter::CompositionMode_SourceOver )
841  return true;
842 
843  return false;
844 }
845 
847 {
848  d->isValid = true;
849  return d->mDataDefinedProperties;
850 }
851 
853 {
854  return d->mDataDefinedProperties;
855 }
856 
857 QSet<QString> QgsTextFormat::referencedFields( const QgsRenderContext &context ) const
858 {
859  QSet< QString > fields = d->mDataDefinedProperties.referencedFields( context.expressionContext(), true );
860  fields.unite( mBufferSettings.referencedFields( context ) );
861  fields.unite( mBackgroundSettings.referencedFields( context ) );
862  fields.unite( mShadowSettings.referencedFields( context ) );
863  fields.unite( mMaskSettings.referencedFields( context ) );
864  return fields;
865 }
866 
868 {
869  d->isValid = true;
870  d->mDataDefinedProperties = collection;
871 }
872 
874 {
875  d->isValid = true;
876  if ( !d->mDataDefinedProperties.hasActiveProperties() )
877  return;
878 
879  QString ddFontFamily;
880  context.expressionContext().setOriginalValueVariable( d->textFont.family() );
881  QVariant exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::Family, context.expressionContext() );
882  if ( !exprVal.isNull() )
883  {
884  QString family = exprVal.toString().trimmed();
886  if ( d->textFont.family() != family )
887  {
888  // testing for ddFontFamily in QFontDatabase.families() may be slow to do for every feature
889  // (i.e. don't use QgsFontUtils::fontFamilyMatchOnSystem( family ) here)
890  if ( QgsFontUtils::fontFamilyOnSystem( family ) )
891  {
892  ddFontFamily = family;
893  }
894  }
895  }
896 
897  // data defined named font style?
898  QString ddFontStyle;
899  context.expressionContext().setOriginalValueVariable( d->textNamedStyle );
900  exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontStyle, context.expressionContext() );
901  if ( !exprVal.isNull() )
902  {
903  QString fontstyle = exprVal.toString().trimmed();
904  ddFontStyle = fontstyle;
905  }
906 
907  bool ddBold = false;
908  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Bold ) )
909  {
910  context.expressionContext().setOriginalValueVariable( d->textFont.bold() );
911  ddBold = d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Bold, context.expressionContext(), false ) ;
912  }
913 
914  bool ddItalic = false;
915  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Italic ) )
916  {
917  context.expressionContext().setOriginalValueVariable( d->textFont.italic() );
918  ddItalic = d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Italic, context.expressionContext(), false );
919  }
920 
921  // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
922  // (currently defaults to what has been read in from layer settings)
923  QFont newFont;
924  QFontDatabase fontDb;
925  QFont appFont = QApplication::font();
926  bool newFontBuilt = false;
927  if ( ddBold || ddItalic )
928  {
929  // new font needs built, since existing style needs removed
930  newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : d->textFont.family() );
931  newFontBuilt = true;
932  newFont.setBold( ddBold );
933  newFont.setItalic( ddItalic );
934  }
935  else if ( !ddFontStyle.isEmpty()
936  && ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
937  {
938  if ( !ddFontFamily.isEmpty() )
939  {
940  // both family and style are different, build font from database
941  QFont styledfont = fontDb.font( ddFontFamily, ddFontStyle, appFont.pointSize() );
942  if ( appFont != styledfont )
943  {
944  newFont = styledfont;
945  newFontBuilt = true;
946  }
947  }
948 
949  // update the font face style
950  QgsFontUtils::updateFontViaStyle( newFontBuilt ? newFont : d->textFont, ddFontStyle );
951  }
952  else if ( !ddFontFamily.isEmpty() )
953  {
954  if ( ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
955  {
956  // just family is different, build font from database
957  QFont styledfont = fontDb.font( ddFontFamily, d->textNamedStyle, appFont.pointSize() );
958  if ( appFont != styledfont )
959  {
960  newFont = styledfont;
961  newFontBuilt = true;
962  }
963  }
964  else
965  {
966  newFont = QFont( ddFontFamily );
967  newFontBuilt = true;
968  }
969  }
970 
971  if ( newFontBuilt )
972  {
973  // copy over existing font settings
974  newFont.setUnderline( d->textFont.underline() );
975  newFont.setStrikeOut( d->textFont.strikeOut() );
976  newFont.setWordSpacing( d->textFont.wordSpacing() );
977  newFont.setLetterSpacing( QFont::AbsoluteSpacing, d->textFont.letterSpacing() );
978  d->textFont = newFont;
979  }
980 
981  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Underline ) )
982  {
983  context.expressionContext().setOriginalValueVariable( d->textFont.underline() );
984  d->textFont.setUnderline( d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Underline, context.expressionContext(), d->textFont.underline() ) );
985  }
986 
987  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Strikeout ) )
988  {
989  context.expressionContext().setOriginalValueVariable( d->textFont.strikeOut() );
990  d->textFont.setStrikeOut( d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Strikeout, context.expressionContext(), d->textFont.strikeOut() ) );
991  }
992 
993  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Color ) )
994  {
996  d->textColor = d->mDataDefinedProperties.valueAsColor( QgsPalLayerSettings::Color, context.expressionContext(), d->textColor );
997  }
998 
999  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Size ) )
1000  {
1002  d->fontSize = d->mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::Size, context.expressionContext(), d->fontSize );
1003  }
1004 
1005  exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontSizeUnit, context.expressionContext() );
1006  if ( !exprVal.isNull() )
1007  {
1008  QString units = exprVal.toString();
1009  if ( !units.isEmpty() )
1010  {
1011  bool ok;
1013  if ( ok )
1014  d->fontSizeUnits = res;
1015  }
1016  }
1017 
1018  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontOpacity ) )
1019  {
1020  context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
1021  const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontOpacity, context.expressionContext(), d->opacity * 100 );
1022  if ( !val.isNull() )
1023  {
1024  d->opacity = val.toDouble() / 100.0;
1025  }
1026  }
1027 
1028 #ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
1029  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontStretchFactor ) )
1030  {
1031  context.expressionContext().setOriginalValueVariable( d->textFont.stretch() );
1032  const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontStretchFactor, context.expressionContext(), d->textFont.stretch() );
1033  if ( !val.isNull() )
1034  {
1035  d->textFont.setStretch( val.toInt() );
1036  }
1037  }
1038 #endif
1039 
1040  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::TextOrientation ) )
1041  {
1042  const QString encoded = QgsTextRendererUtils::encodeTextOrientation( d->orientation );
1043  context.expressionContext().setOriginalValueVariable( encoded );
1044  d->orientation = QgsTextRendererUtils::decodeTextOrientation( d->mDataDefinedProperties.value( QgsPalLayerSettings::TextOrientation, context.expressionContext(), encoded ).toString() );
1045  }
1046 
1047  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontLetterSpacing ) )
1048  {
1049  context.expressionContext().setOriginalValueVariable( d->textFont.letterSpacing() );
1050  const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontLetterSpacing, context.expressionContext(), d->textFont.letterSpacing() );
1051  if ( !val.isNull() )
1052  {
1053  d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, val.toDouble() );
1054  }
1055  }
1056 
1057  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontWordSpacing ) )
1058  {
1059  context.expressionContext().setOriginalValueVariable( d->textFont.wordSpacing() );
1060  const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontWordSpacing, context.expressionContext(), d->textFont.wordSpacing() );
1061  if ( !val.isNull() )
1062  {
1063  d->textFont.setWordSpacing( val.toDouble() );
1064  }
1065  }
1066 
1067  if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontBlendMode ) )
1068  {
1069  exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontBlendMode, context.expressionContext() );
1070  QString blendstr = exprVal.toString().trimmed();
1071  if ( !blendstr.isEmpty() )
1072  d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
1073  }
1074 
1075  mShadowSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1076  mBackgroundSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1077  mBufferSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1078  mMaskSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1079 }
1080 
1081 QPixmap QgsTextFormat::textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText, int padding )
1082 {
1083  QgsTextFormat tempFormat = format;
1084  QPixmap pixmap( size );
1085  pixmap.fill( Qt::transparent );
1086  QPainter painter;
1087  painter.begin( &pixmap );
1088 
1089  painter.setRenderHint( QPainter::Antialiasing );
1090 
1091  QRect rect( 0, 0, size.width(), size.height() );
1092 
1093  // shameless eye candy - use a subtle gradient when drawing background
1094  painter.setPen( Qt::NoPen );
1095  QColor background1 = tempFormat.previewBackgroundColor();
1096  if ( ( background1.lightnessF() < 0.7 ) )
1097  {
1098  background1 = background1.darker( 125 );
1099  }
1100  else
1101  {
1102  background1 = background1.lighter( 125 );
1103  }
1104  QColor background2 = tempFormat.previewBackgroundColor();
1105  QLinearGradient linearGrad( QPointF( 0, 0 ), QPointF( 0, rect.height() ) );
1106  linearGrad.setColorAt( 0, background1 );
1107  linearGrad.setColorAt( 1, background2 );
1108  painter.setBrush( QBrush( linearGrad ) );
1109  if ( size.width() > 30 )
1110  {
1111  painter.drawRoundedRect( rect, 6, 6 );
1112  }
1113  else
1114  {
1115  // don't use rounded rect for small previews
1116  painter.drawRect( rect );
1117  }
1118  painter.setBrush( Qt::NoBrush );
1119  painter.setPen( Qt::NoPen );
1120  padding += 1; // move text away from background border
1121 
1122  QgsRenderContext context;
1123  QgsMapToPixel newCoordXForm;
1124  newCoordXForm.setParameters( 1, 0, 0, 0, 0, 0 );
1125  context.setMapToPixel( newCoordXForm );
1126 
1127 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1128  const double logicalDpiX = QgsApplication::desktop()->logicalDpiX();
1129 #else
1130  QWidget *activeWindow = QApplication::activeWindow();
1131  const double logicalDpiX = activeWindow && activeWindow->screen() ? activeWindow->screen()->logicalDotsPerInchX() : 96.0;
1132 #endif
1133  context.setScaleFactor( logicalDpiX / 25.4 );
1134 
1135  context.setUseAdvancedEffects( true );
1137  context.setPainter( &painter );
1139 
1140  // slightly inset text to account for buffer/background
1141  const double fontSize = context.convertToPainterUnits( tempFormat.size(), tempFormat.sizeUnit(), tempFormat.sizeMapUnitScale() );
1142  double xtrans = 0;
1143  if ( tempFormat.buffer().enabled() )
1144  xtrans = tempFormat.buffer().sizeUnit() == QgsUnitTypes::RenderPercentage
1145  ? fontSize * tempFormat.buffer().size() / 100
1146  : context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() );
1147  if ( tempFormat.background().enabled() && tempFormat.background().sizeType() != QgsTextBackgroundSettings::SizeFixed )
1148  xtrans = std::max( xtrans, context.convertToPainterUnits( tempFormat.background().size().width(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
1149 
1150  double ytrans = 0.0;
1151  if ( tempFormat.buffer().enabled() )
1152  ytrans = std::max( ytrans, tempFormat.buffer().sizeUnit() == QgsUnitTypes::RenderPercentage
1153  ? fontSize * tempFormat.buffer().size() / 100
1154  : context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() ) );
1155  if ( tempFormat.background().enabled() )
1156  ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat.background().size().height(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
1157 
1158  const QStringList text = QStringList() << ( previewText.isEmpty() ? QObject::tr( "Aa" ) : previewText );
1159  const double textHeight = QgsTextRenderer::textHeight( context, tempFormat, text, QgsTextRenderer::Rect );
1160  QRectF textRect = rect;
1161  textRect.setLeft( xtrans + padding );
1162  textRect.setWidth( rect.width() - xtrans - 2 * padding );
1163 
1164  if ( textRect.width() > 2000 )
1165  textRect.setWidth( 2000 - 2 * padding );
1166 
1167  const double bottom = textRect.height() / 2 + textHeight / 2;
1168  textRect.setTop( bottom - textHeight );
1169  textRect.setBottom( bottom );
1170 
1171  QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::AlignCenter, text, context, tempFormat );
1172 
1173  // draw border on top of text
1174  painter.setBrush( Qt::NoBrush );
1175  painter.setPen( QPen( tempFormat.previewBackgroundColor().darker( 150 ), 0 ) );
1176  if ( size.width() > 30 )
1177  {
1178  painter.drawRoundedRect( rect, 6, 6 );
1179  }
1180  else
1181  {
1182  // don't use rounded rect for small previews
1183  painter.drawRect( rect );
1184  }
1185  painter.end();
1186  return pixmap;
1187 }
Capitalization
String capitalization options.
Definition: qgis.h:1611
@ 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.
static QgsFontManager * fontManager()
Returns the application font manager, which manages available fonts and font installation for the QGI...
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
QString processFontFamilyName(const QString &name) const
Processes a font family name, applying any matching fontFamilyReplacements() to the name.
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.
void setForcedItalic(bool forced)
Sets whether the format is set to force an italic style.
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.
bool forcedItalic() const
Returns true if the format is set to force an italic 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.
void setForcedBold(bool forced)
Sets whether the format is set to force a bold style.
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)
bool forcedBold() const
Returns true if the format is set to force a bold style.
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:2260