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