QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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"
24#include "qgspallabeling.h"
25#include "qgsconfig.h"
26#include "qgsfontmanager.h"
27#include "qgsapplication.h"
28#include "qgsunittypes.h"
29
30#include <QFontDatabase>
31#include <QMimeData>
32#include <QWidget>
33#include <QScreen>
34
36{
37 d = new QgsTextSettingsPrivate();
38}
39
41 : mBufferSettings( other.mBufferSettings )
42 , mBackgroundSettings( other.mBackgroundSettings )
43 , mShadowSettings( other.mShadowSettings )
44 , mMaskSettings( other.mMaskSettings )
45 , mTextFontFamily( other.mTextFontFamily )
46 , mTextFontFound( other.mTextFontFound )
47 , d( other.d )
48{
49
50}
51
53{
54 d = other.d;
55 mBufferSettings = other.mBufferSettings;
56 mBackgroundSettings = other.mBackgroundSettings;
57 mShadowSettings = other.mShadowSettings;
58 mMaskSettings = other.mMaskSettings;
59 mTextFontFamily = other.mTextFontFamily;
60 mTextFontFound = other.mTextFontFound;
61 return *this;
62}
63
65{
66
67}
68
69bool QgsTextFormat::operator==( const QgsTextFormat &other ) const
70{
71 if ( d->isValid != other.isValid()
72 || d->textFont != other.font()
73 || namedStyle() != other.namedStyle()
74 || d->fontSizeUnits != other.sizeUnit()
75 || d->fontSizeMapUnitScale != other.sizeMapUnitScale()
76 || d->fontSize != other.size()
77 || d->textColor != other.color()
78 || d->opacity != other.opacity()
79 || d->blendMode != other.blendMode()
80 || d->multilineHeight != other.lineHeight()
81 || d->multilineHeightUnits != other.lineHeightUnit()
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
99bool 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
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
145{
146 d->isValid = true;
147 mShadowSettings = shadowSettings;
148}
149
151{
152 d->isValid = true;
153 return mMaskSettings;
154}
155
157{
158 d->isValid = true;
159 mMaskSettings = maskSettings;
160}
161
163{
164 return d->textFont;
165}
166
167QFont 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
209void 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
224void 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
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
255QStringList QgsTextFormat::families() const
256{
257 return d->families;
258}
259
260void 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
289{
290 return d->fontSize;
291}
292
293void QgsTextFormat::setSize( double size )
294{
295 d->isValid = true;
296 d->fontSize = size;
297}
298
300{
301 return d->textColor;
302}
303
304void QgsTextFormat::setColor( const QColor &color )
305{
306 d->isValid = true;
307 d->textColor = color;
308}
309
311{
312 return d->opacity;
313}
314
315void 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
332QPainter::CompositionMode QgsTextFormat::blendMode() const
333{
334 return d->blendMode;
335}
336
337void QgsTextFormat::setBlendMode( QPainter::CompositionMode mode )
338{
339 d->isValid = true;
340 d->blendMode = mode;
341}
342
344{
345 return d->multilineHeight;
346}
347
348void QgsTextFormat::setLineHeight( double height )
349{
350 d->isValid = true;
351 d->multilineHeight = height;
352}
353
355{
356 return d->multilineHeightUnits;
357}
358
360{
361 d->isValid = true;
362 d->multilineHeightUnits = unit;
363}
364
366{
367 return d->orientation;
368}
369
371{
372 d->isValid = true;
373 d->orientation = orientation;
374}
375
377{
378 // bit of complexity here to maintain API..
379 return d->capitalization == Qgis::Capitalization::MixedCase && d->textFont.capitalization() != QFont::MixedCase
380 ? static_cast< Qgis::Capitalization >( d->textFont.capitalization() )
381 : d->capitalization ;
382}
383
385{
386 d->isValid = true;
387 d->capitalization = capitalization;
388#if defined(HAS_KDE_QT5_SMALL_CAPS_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
389 d->textFont.setCapitalization( capitalization == Qgis::Capitalization::SmallCaps || capitalization == Qgis::Capitalization::AllSmallCaps ? QFont::SmallCaps : QFont::MixedCase );
390#else
391 d->textFont.setCapitalization( QFont::MixedCase );
392#endif
393}
394
396{
397 return d->allowHtmlFormatting;
398}
399
401{
402 d->isValid = true;
403 d->allowHtmlFormatting = allow;
404}
405
407{
408 return d->previewBackgroundColor;
409}
410
412{
413 d->isValid = true;
414 d->previewBackgroundColor = color;
415}
416
418{
419 d->isValid = true;
420 QFont appFont = QApplication::font();
421 mTextFontFamily = QgsApplication::fontManager()->processFontFamilyName( layer->customProperty( QStringLiteral( "labeling/fontFamily" ), QVariant( appFont.family() ) ).toString() );
422 QString fontFamily = mTextFontFamily;
423 if ( mTextFontFamily != appFont.family() && !QgsFontUtils::fontFamilyMatchOnSystem( mTextFontFamily ) )
424 {
425 // trigger to notify about font family substitution
426 mTextFontFound = false;
427
428 // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
429 // currently only defaults to matching algorithm for resolving [foundry], if a font of similar family is found (default for QFont)
430
431 // for now, do not use matching algorithm for substitution if family not found, substitute default instead
432 fontFamily = appFont.family();
433 }
434 else
435 {
436 mTextFontFound = true;
437 }
438
439 if ( !layer->customProperty( QStringLiteral( "labeling/fontSize" ) ).isValid() )
440 {
441 d->fontSize = appFont.pointSizeF();
442 }
443 else
444 {
445 d->fontSize = layer->customProperty( QStringLiteral( "labeling/fontSize" ) ).toDouble();
446 }
447
448 if ( layer->customProperty( QStringLiteral( "labeling/fontSizeUnit" ) ).toString().isEmpty() )
449 {
450 d->fontSizeUnits = layer->customProperty( QStringLiteral( "labeling/fontSizeInMapUnits" ), QVariant( false ) ).toBool() ?
451 Qgis::RenderUnit::MapUnits : Qgis::RenderUnit::Points;
452 }
453 else
454 {
455 bool ok = false;
456 d->fontSizeUnits = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/fontSizeUnit" ) ).toString(), &ok );
457 if ( !ok )
458 d->fontSizeUnits = Qgis::RenderUnit::Points;
459 }
460 if ( layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitScale" ) ).toString().isEmpty() )
461 {
462 //fallback to older property
463 double oldMin = layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitMinScale" ), 0.0 ).toDouble();
464 d->fontSizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
465 double oldMax = layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitMaxScale" ), 0.0 ).toDouble();
466 d->fontSizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
467 }
468 else
469 {
470 d->fontSizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/fontSizeMapUnitScale" ) ).toString() );
471 }
472 int fontWeight = layer->customProperty( QStringLiteral( "labeling/fontWeight" ) ).toInt();
473 bool fontItalic = layer->customProperty( QStringLiteral( "labeling/fontItalic" ) ).toBool();
474 d->textFont = QFont( fontFamily, d->fontSize, fontWeight, fontItalic );
475 d->textNamedStyle = QgsFontUtils::translateNamedStyle( layer->customProperty( QStringLiteral( "labeling/namedStyle" ), QVariant( "" ) ).toString() );
476 QgsFontUtils::updateFontViaStyle( d->textFont, d->textNamedStyle ); // must come after textFont.setPointSizeF()
477 d->capitalization = static_cast< Qgis::Capitalization >( layer->customProperty( QStringLiteral( "labeling/fontCapitals" ), QVariant( 0 ) ).toUInt() );
478 d->textFont.setUnderline( layer->customProperty( QStringLiteral( "labeling/fontUnderline" ) ).toBool() );
479 d->textFont.setStrikeOut( layer->customProperty( QStringLiteral( "labeling/fontStrikeout" ) ).toBool() );
480 d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, layer->customProperty( QStringLiteral( "labeling/fontLetterSpacing" ), QVariant( 0.0 ) ).toDouble() );
481 d->textFont.setWordSpacing( layer->customProperty( QStringLiteral( "labeling/fontWordSpacing" ), QVariant( 0.0 ) ).toDouble() );
482 d->textColor = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/textColor" ), Qt::black, false );
483 if ( layer->customProperty( QStringLiteral( "labeling/textOpacity" ) ).toString().isEmpty() )
484 {
485 d->opacity = ( 1 - layer->customProperty( QStringLiteral( "labeling/textTransp" ) ).toInt() / 100.0 ); //0 -100
486 }
487 else
488 {
489 d->opacity = ( layer->customProperty( QStringLiteral( "labeling/textOpacity" ) ).toDouble() );
490 }
491 d->blendMode = QgsPainting::getCompositionMode(
492 static_cast< Qgis::BlendMode >( layer->customProperty( QStringLiteral( "labeling/blendMode" ), QVariant( static_cast< int >( Qgis::BlendMode::Normal ) ) ).toUInt() ) );
493 d->multilineHeight = layer->customProperty( QStringLiteral( "labeling/multilineHeight" ), QVariant( 1.0 ) ).toDouble();
494 d->previewBackgroundColor = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/previewBkgrdColor" ), QColor( 255, 255, 255 ), false );
495
496 mBufferSettings.readFromLayer( layer );
497 mShadowSettings.readFromLayer( layer );
498 mBackgroundSettings.readFromLayer( layer );
499}
500
501void QgsTextFormat::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
502{
503 d->isValid = true;
504 QDomElement textStyleElem;
505 if ( elem.nodeName() == QLatin1String( "text-style" ) )
506 textStyleElem = elem;
507 else
508 textStyleElem = elem.firstChildElement( QStringLiteral( "text-style" ) );
509 QFont appFont = QApplication::font();
510 mTextFontFamily = QgsApplication::fontManager()->processFontFamilyName( textStyleElem.attribute( QStringLiteral( "fontFamily" ), appFont.family() ) );
511 QString fontFamily = mTextFontFamily;
512
513 const QDomElement familiesElem = textStyleElem.firstChildElement( QStringLiteral( "families" ) );
514 const QDomNodeList familyNodes = familiesElem.childNodes();
515 QStringList families;
516 families.reserve( familyNodes.size() );
517 for ( int i = 0; i < familyNodes.count(); ++i )
518 {
519 const QDomElement familyElem = familyNodes.at( i ).toElement();
520 families << familyElem.attribute( QStringLiteral( "name" ) );
521 }
522 d->families = families;
523
524 mTextFontFound = false;
525 QString matched;
526 if ( mTextFontFamily != appFont.family() && !QgsFontUtils::fontFamilyMatchOnSystem( mTextFontFamily ) )
527 {
528 if ( QgsApplication::fontManager()->tryToDownloadFontFamily( mTextFontFamily, matched ) )
529 {
530 mTextFontFound = true;
531 }
532 else
533 {
534 for ( const QString &family : std::as_const( families ) )
535 {
536 const QString processedFamily = QgsApplication::fontManager()->processFontFamilyName( family );
537 if ( QgsFontUtils::fontFamilyMatchOnSystem( processedFamily ) ||
538 QgsApplication::fontManager()->tryToDownloadFontFamily( processedFamily, matched ) )
539 {
540 mTextFontFound = true;
541 fontFamily = processedFamily;
542 break;
543 }
544 }
545
546 if ( !mTextFontFound )
547 {
548 // couldn't even find a matching font in the backup list -- substitute default instead
549 fontFamily = appFont.family();
550 }
551 }
552 }
553 else
554 {
555 mTextFontFound = true;
556 }
557
558 if ( !mTextFontFound )
559 {
560 context.pushMessage( QObject::tr( "Font “%1” not available on system" ).arg( mTextFontFamily ) );
561 }
562
563 if ( textStyleElem.hasAttribute( QStringLiteral( "fontSize" ) ) )
564 {
565 d->fontSize = textStyleElem.attribute( QStringLiteral( "fontSize" ) ).toDouble();
566 }
567 else
568 {
569 d->fontSize = appFont.pointSizeF();
570 }
571
572 if ( !textStyleElem.hasAttribute( QStringLiteral( "fontSizeUnit" ) ) )
573 {
574 d->fontSizeUnits = textStyleElem.attribute( QStringLiteral( "fontSizeInMapUnits" ) ).toUInt() == 0 ? Qgis::RenderUnit::Points
575 : Qgis::RenderUnit::MapUnits;
576 }
577 else
578 {
579 d->fontSizeUnits = QgsUnitTypes::decodeRenderUnit( textStyleElem.attribute( QStringLiteral( "fontSizeUnit" ) ) );
580 }
581
582 if ( !textStyleElem.hasAttribute( QStringLiteral( "fontSizeMapUnitScale" ) ) )
583 {
584 //fallback to older property
585 double oldMin = textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
586 d->fontSizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0;
587 double oldMax = textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
588 d->fontSizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0;
589 }
590 else
591 {
592 d->fontSizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( textStyleElem.attribute( QStringLiteral( "fontSizeMapUnitScale" ) ) );
593 }
594 int fontWeight = textStyleElem.attribute( QStringLiteral( "fontWeight" ) ).toInt();
595 bool fontItalic = textStyleElem.attribute( QStringLiteral( "fontItalic" ) ).toInt();
596 d->textFont = QFont( fontFamily, d->fontSize, fontWeight, fontItalic );
597 d->textFont.setPointSizeF( d->fontSize ); //double precision needed because of map units
598 d->textNamedStyle = QgsFontUtils::translateNamedStyle( textStyleElem.attribute( QStringLiteral( "namedStyle" ) ) );
599 QgsFontUtils::updateFontViaStyle( d->textFont, d->textNamedStyle ); // must come after textFont.setPointSizeF()
600 d->forcedBold = textStyleElem.attribute( QStringLiteral( "forcedBold" ) ).toInt();
601 d->forcedItalic = textStyleElem.attribute( QStringLiteral( "forcedItalic" ) ).toInt();
602 d->textFont.setUnderline( textStyleElem.attribute( QStringLiteral( "fontUnderline" ) ).toInt() );
603 d->textFont.setStrikeOut( textStyleElem.attribute( QStringLiteral( "fontStrikeout" ) ).toInt() );
604 d->textFont.setKerning( textStyleElem.attribute( QStringLiteral( "fontKerning" ), QStringLiteral( "1" ) ).toInt() );
605 d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, textStyleElem.attribute( QStringLiteral( "fontLetterSpacing" ), QStringLiteral( "0" ) ).toDouble() );
606 d->textFont.setWordSpacing( textStyleElem.attribute( QStringLiteral( "fontWordSpacing" ), QStringLiteral( "0" ) ).toDouble() );
607 d->textColor = QgsSymbolLayerUtils::decodeColor( textStyleElem.attribute( QStringLiteral( "textColor" ), QgsSymbolLayerUtils::encodeColor( Qt::black ) ) );
608 if ( !textStyleElem.hasAttribute( QStringLiteral( "textOpacity" ) ) )
609 {
610 d->opacity = ( 1 - textStyleElem.attribute( QStringLiteral( "textTransp" ) ).toInt() / 100.0 ); //0 -100
611 }
612 else
613 {
614 d->opacity = ( textStyleElem.attribute( QStringLiteral( "textOpacity" ) ).toDouble() );
615 }
616#ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
617 d->textFont.setStretch( textStyleElem.attribute( QStringLiteral( "stretchFactor" ), QStringLiteral( "100" ) ).toInt() );
618#endif
619 d->orientation = QgsTextRendererUtils::decodeTextOrientation( textStyleElem.attribute( QStringLiteral( "textOrientation" ) ) );
620 d->previewBackgroundColor = QgsSymbolLayerUtils::decodeColor( textStyleElem.attribute( QStringLiteral( "previewBkgrdColor" ), QgsSymbolLayerUtils::encodeColor( Qt::white ) ) );
621
622 d->blendMode = QgsPainting::getCompositionMode(
623 static_cast< Qgis::BlendMode >( textStyleElem.attribute( QStringLiteral( "blendMode" ), QString::number( static_cast< int >( Qgis::BlendMode::Normal ) ) ).toUInt() ) );
624
625 if ( !textStyleElem.hasAttribute( QStringLiteral( "multilineHeight" ) ) )
626 {
627 QDomElement textFormatElem = elem.firstChildElement( QStringLiteral( "text-format" ) );
628 d->multilineHeight = textFormatElem.attribute( QStringLiteral( "multilineHeight" ), QStringLiteral( "1" ) ).toDouble();
629 }
630 else
631 {
632 d->multilineHeight = textStyleElem.attribute( QStringLiteral( "multilineHeight" ), QStringLiteral( "1" ) ).toDouble();
633 }
634 bool ok = false;
635 d->multilineHeightUnits = QgsUnitTypes::decodeRenderUnit( textStyleElem.attribute( QStringLiteral( "multilineHeightUnit" ), QStringLiteral( "percent" ) ), &ok );
636
637 if ( textStyleElem.hasAttribute( QStringLiteral( "capitalization" ) ) )
638 d->capitalization = static_cast< Qgis::Capitalization >( textStyleElem.attribute( QStringLiteral( "capitalization" ), QString::number( static_cast< int >( Qgis::Capitalization::MixedCase ) ) ).toInt() );
639 else
640 d->capitalization = static_cast< Qgis::Capitalization >( textStyleElem.attribute( QStringLiteral( "fontCapitals" ), QStringLiteral( "0" ) ).toUInt() );
641
642 if ( d->capitalization == Qgis::Capitalization::SmallCaps || d->capitalization == Qgis::Capitalization::AllSmallCaps )
643 d->textFont.setCapitalization( QFont::SmallCaps );
644
645 d->allowHtmlFormatting = textStyleElem.attribute( QStringLiteral( "allowHtml" ), QStringLiteral( "0" ) ).toInt();
646
647 if ( textStyleElem.firstChildElement( QStringLiteral( "text-buffer" ) ).isNull() )
648 {
649 mBufferSettings.readXml( elem );
650 }
651 else
652 {
653 mBufferSettings.readXml( textStyleElem );
654 }
655 if ( textStyleElem.firstChildElement( QStringLiteral( "text-mask" ) ).isNull() )
656 {
657 mMaskSettings.readXml( elem );
658 }
659 else
660 {
661 mMaskSettings.readXml( textStyleElem );
662 }
663 if ( textStyleElem.firstChildElement( QStringLiteral( "shadow" ) ).isNull() )
664 {
665 mShadowSettings.readXml( elem );
666 }
667 else
668 {
669 mShadowSettings.readXml( textStyleElem );
670 }
671 if ( textStyleElem.firstChildElement( QStringLiteral( "background" ) ).isNull() )
672 {
673 mBackgroundSettings.readXml( elem, context );
674 }
675 else
676 {
677 mBackgroundSettings.readXml( textStyleElem, context );
678 }
679
680 QDomElement ddElem = textStyleElem.firstChildElement( QStringLiteral( "dd_properties" ) );
681 if ( ddElem.isNull() )
682 {
683 ddElem = elem.firstChildElement( QStringLiteral( "dd_properties" ) );
684 }
685 if ( !ddElem.isNull() )
686 {
687 d->mDataDefinedProperties.readXml( ddElem, QgsPalLayerSettings::propertyDefinitions() );
688 mBackgroundSettings.upgradeDataDefinedProperties( d->mDataDefinedProperties );
689 }
690 else
691 {
692 d->mDataDefinedProperties.clear();
693 }
694}
695
696QDomElement QgsTextFormat::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
697{
698 // text style
699 QDomElement textStyleElem = doc.createElement( QStringLiteral( "text-style" ) );
700 textStyleElem.setAttribute( QStringLiteral( "fontFamily" ), d->textFont.family() );
701
702 QDomElement familiesElem = doc.createElement( QStringLiteral( "families" ) );
703 for ( const QString &family : std::as_const( d->families ) )
704 {
705 QDomElement familyElem = doc.createElement( QStringLiteral( "family" ) );
706 familyElem.setAttribute( QStringLiteral( "name" ), family );
707 familiesElem.appendChild( familyElem );
708 }
709 textStyleElem.appendChild( familiesElem );
710
711 textStyleElem.setAttribute( QStringLiteral( "namedStyle" ), QgsFontUtils::untranslateNamedStyle( d->textNamedStyle ) );
712 textStyleElem.setAttribute( QStringLiteral( "fontSize" ), d->fontSize );
713 textStyleElem.setAttribute( QStringLiteral( "fontSizeUnit" ), QgsUnitTypes::encodeUnit( d->fontSizeUnits ) );
714 textStyleElem.setAttribute( QStringLiteral( "fontSizeMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->fontSizeMapUnitScale ) );
715 textStyleElem.setAttribute( QStringLiteral( "fontWeight" ), d->textFont.weight() );
716 textStyleElem.setAttribute( QStringLiteral( "fontItalic" ), d->textFont.italic() );
717 textStyleElem.setAttribute( QStringLiteral( "fontStrikeout" ), d->textFont.strikeOut() );
718 textStyleElem.setAttribute( QStringLiteral( "fontUnderline" ), d->textFont.underline() );
719 textStyleElem.setAttribute( QStringLiteral( "forcedBold" ), d->forcedBold );
720 textStyleElem.setAttribute( QStringLiteral( "forcedItalic" ), d->forcedItalic );
721 textStyleElem.setAttribute( QStringLiteral( "textColor" ), QgsSymbolLayerUtils::encodeColor( d->textColor ) );
722 textStyleElem.setAttribute( QStringLiteral( "previewBkgrdColor" ), QgsSymbolLayerUtils::encodeColor( d->previewBackgroundColor ) );
723 textStyleElem.setAttribute( QStringLiteral( "fontLetterSpacing" ), d->textFont.letterSpacing() );
724 textStyleElem.setAttribute( QStringLiteral( "fontWordSpacing" ), d->textFont.wordSpacing() );
725 textStyleElem.setAttribute( QStringLiteral( "fontKerning" ), d->textFont.kerning() );
726 textStyleElem.setAttribute( QStringLiteral( "textOpacity" ), d->opacity );
727#ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
728 if ( d->textFont.stretch() > 0 )
729 textStyleElem.setAttribute( QStringLiteral( "stretchFactor" ), d->textFont.stretch() );
730#endif
731 textStyleElem.setAttribute( QStringLiteral( "textOrientation" ), QgsTextRendererUtils::encodeTextOrientation( d->orientation ) );
732 textStyleElem.setAttribute( QStringLiteral( "blendMode" ), static_cast< int >( QgsPainting::getBlendModeEnum( d->blendMode ) ) );
733 textStyleElem.setAttribute( QStringLiteral( "multilineHeight" ), d->multilineHeight );
734 textStyleElem.setAttribute( QStringLiteral( "multilineHeightUnit" ), QgsUnitTypes::encodeUnit( d->multilineHeightUnits ) );
735
736 textStyleElem.setAttribute( QStringLiteral( "allowHtml" ), d->allowHtmlFormatting ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
737 textStyleElem.setAttribute( QStringLiteral( "capitalization" ), QString::number( static_cast< int >( d->capitalization ) ) );
738
739 QDomElement ddElem = doc.createElement( QStringLiteral( "dd_properties" ) );
740 d->mDataDefinedProperties.writeXml( ddElem, QgsPalLayerSettings::propertyDefinitions() );
741
742 textStyleElem.appendChild( mBufferSettings.writeXml( doc ) );
743 textStyleElem.appendChild( mMaskSettings.writeXml( doc ) );
744 textStyleElem.appendChild( mBackgroundSettings.writeXml( doc, context ) );
745 textStyleElem.appendChild( mShadowSettings.writeXml( doc ) );
746 textStyleElem.appendChild( ddElem );
747
748 return textStyleElem;
749}
750
752{
753 //set both the mime color data, and the text (format settings).
754
755 QMimeData *mimeData = new QMimeData;
756 mimeData->setColorData( QVariant( color() ) );
757
758 QgsReadWriteContext rwContext;
759 QDomDocument textDoc;
760 QDomElement textElem = writeXml( textDoc, rwContext );
761 textDoc.appendChild( textElem );
762 mimeData->setText( textDoc.toString() );
763
764 return mimeData;
765}
766
768{
769 QgsTextFormat format;
770 format.setFont( font );
771 if ( font.pointSizeF() > 0 )
772 {
773 format.setSize( font.pointSizeF() );
774 format.setSizeUnit( Qgis::RenderUnit::Points );
775 }
776 else if ( font.pixelSize() > 0 )
777 {
778 format.setSize( font.pixelSize() );
779 format.setSizeUnit( Qgis::RenderUnit::Pixels );
780 }
781
782 return format;
783}
784
786{
787 QFont f = font();
788 switch ( sizeUnit() )
789 {
790 case Qgis::RenderUnit::Points:
791 f.setPointSizeF( size() );
792 break;
793
794 case Qgis::RenderUnit::Millimeters:
795 f.setPointSizeF( size() * 2.83464567 );
796 break;
797
798 case Qgis::RenderUnit::Inches:
799 f.setPointSizeF( size() * 72 );
800 break;
801
802 case Qgis::RenderUnit::Pixels:
803 f.setPixelSize( static_cast< int >( std::round( size() ) ) );
804 break;
805
806 case Qgis::RenderUnit::MapUnits:
807 case Qgis::RenderUnit::MetersInMapUnits:
808 case Qgis::RenderUnit::Unknown:
809 case Qgis::RenderUnit::Percentage:
810 // no meaning here
811 break;
812 }
813 return f;
814}
815
816QgsTextFormat QgsTextFormat::fromMimeData( const QMimeData *data, bool *ok )
817{
818 if ( ok )
819 *ok = false;
820 QgsTextFormat format;
821 if ( !data )
822 return format;
823
824 QString text = data->text();
825 if ( !text.isEmpty() )
826 {
827 QDomDocument doc;
828 QDomElement elem;
829 QgsReadWriteContext rwContext;
830
831 if ( doc.setContent( text ) )
832 {
833 elem = doc.documentElement();
834
835 format.readXml( elem, rwContext );
836 if ( ok )
837 *ok = true;
838 return format;
839 }
840 }
841 return format;
842}
843
845{
846 if ( d->blendMode != QPainter::CompositionMode_SourceOver )
847 return true;
848
849 if ( mBufferSettings.enabled() && mBufferSettings.blendMode() != QPainter::CompositionMode_SourceOver )
850 return true;
851
852 if ( mBackgroundSettings.enabled() && mBackgroundSettings.blendMode() != QPainter::CompositionMode_SourceOver )
853 return true;
854
855 if ( mShadowSettings.enabled() && mShadowSettings.blendMode() != QPainter::CompositionMode_SourceOver )
856 return true;
857
858 return false;
859}
860
862{
863 d->isValid = true;
864 return d->mDataDefinedProperties;
865}
866
868{
869 return d->mDataDefinedProperties;
870}
871
872QSet<QString> QgsTextFormat::referencedFields( const QgsRenderContext &context ) const
873{
874 QSet< QString > fields = d->mDataDefinedProperties.referencedFields( context.expressionContext(), true );
875 fields.unite( mBufferSettings.referencedFields( context ) );
876 fields.unite( mBackgroundSettings.referencedFields( context ) );
877 fields.unite( mShadowSettings.referencedFields( context ) );
878 fields.unite( mMaskSettings.referencedFields( context ) );
879 return fields;
880}
881
883{
884 d->isValid = true;
885 d->mDataDefinedProperties = collection;
886}
887
889{
890 d->isValid = true;
891 if ( !d->mDataDefinedProperties.hasActiveProperties() )
892 return;
893
894 QString ddFontFamily;
895 context.expressionContext().setOriginalValueVariable( d->textFont.family() );
896 QVariant exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::Family, context.expressionContext() );
897 if ( !QgsVariantUtils::isNull( exprVal ) )
898 {
899 QString family = exprVal.toString().trimmed();
901 if ( d->textFont.family() != family )
902 {
903 // testing for ddFontFamily in QFontDatabase.families() may be slow to do for every feature
904 // (i.e. don't use QgsFontUtils::fontFamilyMatchOnSystem( family ) here)
905 if ( QgsFontUtils::fontFamilyOnSystem( family ) )
906 {
907 ddFontFamily = family;
908 }
909 }
910 }
911
912 // data defined named font style?
913 QString ddFontStyle;
914 context.expressionContext().setOriginalValueVariable( d->textNamedStyle );
915 exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontStyle, context.expressionContext() );
916 if ( !QgsVariantUtils::isNull( exprVal ) )
917 {
918 QString fontstyle = exprVal.toString().trimmed();
919 ddFontStyle = fontstyle;
920 }
921
922 bool ddBold = false;
923 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Bold ) )
924 {
925 context.expressionContext().setOriginalValueVariable( d->textFont.bold() );
926 ddBold = d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Bold, context.expressionContext(), false ) ;
927 }
928
929 bool ddItalic = false;
930 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Italic ) )
931 {
932 context.expressionContext().setOriginalValueVariable( d->textFont.italic() );
933 ddItalic = d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Italic, context.expressionContext(), false );
934 }
935
936 // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
937 // (currently defaults to what has been read in from layer settings)
938 QFont newFont;
939 QFontDatabase fontDb;
940 QFont appFont = QApplication::font();
941 bool newFontBuilt = false;
942 if ( ddBold || ddItalic )
943 {
944 // new font needs built, since existing style needs removed
945 newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : d->textFont.family() );
946 newFontBuilt = true;
947 newFont.setBold( ddBold );
948 newFont.setItalic( ddItalic );
949 }
950 else if ( !ddFontStyle.isEmpty()
951 && ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
952 {
953 if ( !ddFontFamily.isEmpty() )
954 {
955 // both family and style are different, build font from database
956 QFont styledfont = fontDb.font( ddFontFamily, ddFontStyle, appFont.pointSize() );
957 if ( appFont != styledfont )
958 {
959 newFont = styledfont;
960 newFontBuilt = true;
961 }
962 }
963
964 // update the font face style
965 QgsFontUtils::updateFontViaStyle( newFontBuilt ? newFont : d->textFont, ddFontStyle );
966 }
967 else if ( !ddFontFamily.isEmpty() )
968 {
969 if ( ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
970 {
971 // just family is different, build font from database
972 QFont styledfont = fontDb.font( ddFontFamily, d->textNamedStyle, appFont.pointSize() );
973 if ( appFont != styledfont )
974 {
975 newFont = styledfont;
976 newFontBuilt = true;
977 }
978 }
979 else
980 {
981 newFont = QFont( ddFontFamily );
982 newFontBuilt = true;
983 }
984 }
985
986 if ( newFontBuilt )
987 {
988 // copy over existing font settings
989 newFont.setUnderline( d->textFont.underline() );
990 newFont.setStrikeOut( d->textFont.strikeOut() );
991 newFont.setWordSpacing( d->textFont.wordSpacing() );
992 newFont.setLetterSpacing( QFont::AbsoluteSpacing, d->textFont.letterSpacing() );
993 d->textFont = newFont;
994 }
995
996 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Underline ) )
997 {
998 context.expressionContext().setOriginalValueVariable( d->textFont.underline() );
999 d->textFont.setUnderline( d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Underline, context.expressionContext(), d->textFont.underline() ) );
1000 }
1001
1002 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Strikeout ) )
1003 {
1004 context.expressionContext().setOriginalValueVariable( d->textFont.strikeOut() );
1005 d->textFont.setStrikeOut( d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Strikeout, context.expressionContext(), d->textFont.strikeOut() ) );
1006 }
1007
1008 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Color ) )
1009 {
1011 d->textColor = d->mDataDefinedProperties.valueAsColor( QgsPalLayerSettings::Color, context.expressionContext(), d->textColor );
1012 }
1013
1014 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Size ) )
1015 {
1017 d->fontSize = d->mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::Size, context.expressionContext(), d->fontSize );
1018 }
1019
1020 exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontSizeUnit, context.expressionContext() );
1021 if ( !QgsVariantUtils::isNull( exprVal ) )
1022 {
1023 QString units = exprVal.toString();
1024 if ( !units.isEmpty() )
1025 {
1026 bool ok;
1028 if ( ok )
1029 d->fontSizeUnits = res;
1030 }
1031 }
1032
1033 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontOpacity ) )
1034 {
1035 context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
1036 const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontOpacity, context.expressionContext(), d->opacity * 100 );
1037 if ( !QgsVariantUtils::isNull( val ) )
1038 {
1039 d->opacity = val.toDouble() / 100.0;
1040 }
1041 }
1042
1043#ifdef HAS_KDE_QT5_FONT_STRETCH_FIX
1044 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontStretchFactor ) )
1045 {
1046 context.expressionContext().setOriginalValueVariable( d->textFont.stretch() );
1047 const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontStretchFactor, context.expressionContext(), d->textFont.stretch() );
1048 if ( !QgsVariantUtils::isNull( val ) )
1049 {
1050 d->textFont.setStretch( val.toInt() );
1051 }
1052 }
1053#endif
1054
1055 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::TextOrientation ) )
1056 {
1057 const QString encoded = QgsTextRendererUtils::encodeTextOrientation( d->orientation );
1058 context.expressionContext().setOriginalValueVariable( encoded );
1059 d->orientation = QgsTextRendererUtils::decodeTextOrientation( d->mDataDefinedProperties.value( QgsPalLayerSettings::TextOrientation, context.expressionContext(), encoded ).toString() );
1060 }
1061
1062 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontLetterSpacing ) )
1063 {
1064 context.expressionContext().setOriginalValueVariable( d->textFont.letterSpacing() );
1065 const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontLetterSpacing, context.expressionContext(), d->textFont.letterSpacing() );
1066 if ( !QgsVariantUtils::isNull( val ) )
1067 {
1068 d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, val.toDouble() );
1069 }
1070 }
1071
1072 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontWordSpacing ) )
1073 {
1074 context.expressionContext().setOriginalValueVariable( d->textFont.wordSpacing() );
1075 const QVariant val = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontWordSpacing, context.expressionContext(), d->textFont.wordSpacing() );
1076 if ( !QgsVariantUtils::isNull( val ) )
1077 {
1078 d->textFont.setWordSpacing( val.toDouble() );
1079 }
1080 }
1081
1082 if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontBlendMode ) )
1083 {
1084 exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontBlendMode, context.expressionContext() );
1085 QString blendstr = exprVal.toString().trimmed();
1086 if ( !blendstr.isEmpty() )
1087 d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
1088 }
1089
1090 mShadowSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1091 mBackgroundSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1092 mBufferSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1093 mMaskSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
1094}
1095
1096QPixmap QgsTextFormat::textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText, int padding )
1097{
1098 QgsTextFormat tempFormat = format;
1099 QPixmap pixmap( size );
1100 pixmap.fill( Qt::transparent );
1101 QPainter painter;
1102 painter.begin( &pixmap );
1103
1104 painter.setRenderHint( QPainter::Antialiasing );
1105
1106 QRect rect( 0, 0, size.width(), size.height() );
1107
1108 // shameless eye candy - use a subtle gradient when drawing background
1109 painter.setPen( Qt::NoPen );
1110 QColor background1 = tempFormat.previewBackgroundColor();
1111 if ( ( background1.lightnessF() < 0.7 ) )
1112 {
1113 background1 = background1.darker( 125 );
1114 }
1115 else
1116 {
1117 background1 = background1.lighter( 125 );
1118 }
1119 QColor background2 = tempFormat.previewBackgroundColor();
1120 QLinearGradient linearGrad( QPointF( 0, 0 ), QPointF( 0, rect.height() ) );
1121 linearGrad.setColorAt( 0, background1 );
1122 linearGrad.setColorAt( 1, background2 );
1123 painter.setBrush( QBrush( linearGrad ) );
1124 if ( size.width() > 30 )
1125 {
1126 painter.drawRoundedRect( rect, 6, 6 );
1127 }
1128 else
1129 {
1130 // don't use rounded rect for small previews
1131 painter.drawRect( rect );
1132 }
1133 painter.setBrush( Qt::NoBrush );
1134 painter.setPen( Qt::NoPen );
1135 padding += 1; // move text away from background border
1136
1137 QgsRenderContext context;
1138 QgsMapToPixel newCoordXForm;
1139 newCoordXForm.setParameters( 1, 0, 0, 0, 0, 0 );
1140 context.setMapToPixel( newCoordXForm );
1141
1142 QWidget *activeWindow = QApplication::activeWindow();
1143 const double logicalDpiX = activeWindow && activeWindow->screen() ? activeWindow->screen()->logicalDotsPerInchX() : 96.0;
1144 context.setScaleFactor( logicalDpiX / 25.4 );
1145
1146 context.setUseAdvancedEffects( true );
1148 context.setPainter( &painter );
1150
1151 // slightly inset text to account for buffer/background
1152 const double fontSize = context.convertToPainterUnits( tempFormat.size(), tempFormat.sizeUnit(), tempFormat.sizeMapUnitScale() );
1153 double xtrans = 0;
1154 if ( tempFormat.buffer().enabled() )
1155 xtrans = tempFormat.buffer().sizeUnit() == Qgis::RenderUnit::Percentage
1156 ? fontSize * tempFormat.buffer().size() / 100
1157 : context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() );
1158 if ( tempFormat.background().enabled() && tempFormat.background().sizeType() != QgsTextBackgroundSettings::SizeFixed )
1159 xtrans = std::max( xtrans, context.convertToPainterUnits( tempFormat.background().size().width(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
1160
1161 double ytrans = 0.0;
1162 if ( tempFormat.buffer().enabled() )
1163 ytrans = std::max( ytrans, tempFormat.buffer().sizeUnit() == Qgis::RenderUnit::Percentage
1164 ? fontSize * tempFormat.buffer().size() / 100
1165 : context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() ) );
1166 if ( tempFormat.background().enabled() )
1167 ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat.background().size().height(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
1168
1169 const QStringList text = QStringList() << ( previewText.isEmpty() ? QObject::tr( "Aa" ) : previewText );
1170 const double textHeight = QgsTextRenderer::textHeight( context, tempFormat, text, Qgis::TextLayoutMode::Rectangle );
1171 QRectF textRect = rect;
1172 textRect.setLeft( xtrans + padding );
1173 textRect.setWidth( rect.width() - xtrans - 2 * padding );
1174
1175 if ( textRect.width() > 2000 )
1176 textRect.setWidth( 2000 - 2 * padding );
1177
1178 const double bottom = textRect.height() / 2 + textHeight / 2;
1179 textRect.setTop( bottom - textHeight );
1180 textRect.setBottom( bottom );
1181
1182 QgsTextRenderer::drawText( textRect, 0, Qgis::TextHorizontalAlignment::Center, text, context, tempFormat );
1183
1184 // draw border on top of text
1185 painter.setBrush( Qt::NoBrush );
1186 painter.setPen( QPen( tempFormat.previewBackgroundColor().darker( 150 ), 0 ) );
1187 if ( size.width() > 30 )
1188 {
1189 painter.drawRoundedRect( rect, 6, 6 );
1190 }
1191 else
1192 {
1193 // don't use rounded rect for small previews
1194 painter.drawRect( rect );
1195 }
1196 painter.end();
1197 return pixmap;
1198}
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition: qgis.h:2978
Capitalization
String capitalization options.
Definition: qgis.h:2150
@ 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)
TextOrientation
Text orientations.
Definition: qgis.h:1786
RenderUnit
Rendering size units.
Definition: qgis.h:3176
@ 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 Qgis::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QPainter::CompositionMode getCompositionMode(Qgis::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
@ 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.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QgsExpressionContext & expressionContext()
Gets the expression context.
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.
Qgis::RenderUnit sizeUnit() const
Returns the units used for the shape's size.
Container for settings relating to a text buffer.
Qgis::RenderUnit sizeUnit() const
Returns the units for the buffer size.
void readFromLayer(QgsVectorLayer *layer)
Reads settings from a layer's custom properties (for QGIS 2.x projects).
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
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.
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 setOrientation(Qgis::TextOrientation orientation)
Sets the orientation for the text.
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.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
int stretchFactor() const
Returns the text's stretch factor.
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
void setAllowHtmlFormatting(bool allow)
Sets whether text should be treated as a HTML document and HTML tags should be used for formatting th...
void setLineHeightUnit(Qgis::RenderUnit unit)
Sets the unit for the line height for text.
Qgis::RenderUnit lineHeightUnit() const
Returns the units for the line height for text.
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.
Qgis::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
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.
bool operator!=(const QgsTextFormat &other) const
double opacity() const
Returns the text's opacity.
Qgis::TextOrientation orientation() const
Returns the orientation of the text.
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 Qgis::TextOrientation decodeTextOrientation(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of 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 QString encodeTextOrientation(Qgis::TextOrientation orientation)
Encodes a text orientation.
static int sizeToPixel(double size, const QgsRenderContext &c, Qgis::RenderUnit unit, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale())
Calculates pixel size (considering output size should be in pixel or map units, scale factors and opt...
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
Draws text within a rectangle using the specified settings.
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
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 Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
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:3509