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