1 /***************************************************************************
2   qgstextmasksettings.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 "qgstextmasksettings.h"
17 #include "qgstextrenderer_p.h"
18 #include "qgspallabeling.h"
19 #include "qgssymbollayerutils.h"
20 #include "qgspainteffectregistry.h"
21 
QgsTextMaskSettings()22 QgsTextMaskSettings::QgsTextMaskSettings()
23 {
24   d = new QgsTextMaskSettingsPrivate();
25 }
26 
27 QgsTextMaskSettings::~QgsTextMaskSettings() = default;
28 
QgsTextMaskSettings(const QgsTextMaskSettings & other)29 QgsTextMaskSettings::QgsTextMaskSettings( const QgsTextMaskSettings &other ) //NOLINT
30   : d( other.d )
31 {
32 }
33 
operator =(const QgsTextMaskSettings & other)34 QgsTextMaskSettings &QgsTextMaskSettings::operator=( const QgsTextMaskSettings &other )  //NOLINT
35 {
36   d = other.d;
37   return *this;
38 }
39 
operator ==(const QgsTextMaskSettings & other) const40 bool QgsTextMaskSettings::operator==( const QgsTextMaskSettings &other ) const
41 {
42   if ( d->enabled != other.enabled()
43        || d->type != other.type()
44        || d->size != other.size()
45        || d->sizeUnit != other.sizeUnit()
46        || d->sizeMapUnitScale != other.sizeMapUnitScale()
47        || d->joinStyle != other.joinStyle()
48        || d->opacity != other.opacity()
49        || d->maskedSymbolLayers != other.maskedSymbolLayers() )
50     return false;
51 
52   if ( static_cast< bool >( d->paintEffect ) != static_cast< bool >( other.paintEffect() )
53        || ( d->paintEffect && d->paintEffect->properties() != other.paintEffect()->properties() ) )
54     return false;
55 
56   return true;
57 }
58 
operator !=(const QgsTextMaskSettings & other) const59 bool QgsTextMaskSettings::operator!=( const QgsTextMaskSettings &other ) const
60 {
61   return !( *this == other );
62 }
63 
enabled() const64 bool QgsTextMaskSettings::enabled() const
65 {
66   return d->enabled;
67 }
68 
setEnabled(bool enabled)69 void QgsTextMaskSettings::setEnabled( bool enabled )
70 {
71   d->enabled = enabled;
72 }
73 
type() const74 QgsTextMaskSettings::MaskType QgsTextMaskSettings::type() const
75 {
76   return d->type;
77 }
78 
setType(QgsTextMaskSettings::MaskType type)79 void QgsTextMaskSettings::setType( QgsTextMaskSettings::MaskType type )
80 {
81   d->type = type;
82 }
83 
84 
size() const85 double QgsTextMaskSettings::size() const
86 {
87   return d->size;
88 }
89 
setSize(double size)90 void QgsTextMaskSettings::setSize( double size )
91 {
92   d->size = size;
93 }
94 
sizeUnit() const95 QgsUnitTypes::RenderUnit QgsTextMaskSettings::sizeUnit() const
96 {
97   return d->sizeUnit;
98 }
99 
setSizeUnit(QgsUnitTypes::RenderUnit unit)100 void QgsTextMaskSettings::setSizeUnit( QgsUnitTypes::RenderUnit unit )
101 {
102   d->sizeUnit = unit;
103 }
104 
sizeMapUnitScale() const105 QgsMapUnitScale QgsTextMaskSettings::sizeMapUnitScale() const
106 {
107   return d->sizeMapUnitScale;
108 }
109 
setSizeMapUnitScale(const QgsMapUnitScale & scale)110 void QgsTextMaskSettings::setSizeMapUnitScale( const QgsMapUnitScale &scale )
111 {
112   d->sizeMapUnitScale = scale;
113 }
114 
joinStyle() const115 Qt::PenJoinStyle QgsTextMaskSettings::joinStyle() const
116 {
117   return d->joinStyle;
118 }
119 
setJoinStyle(Qt::PenJoinStyle style)120 void QgsTextMaskSettings::setJoinStyle( Qt::PenJoinStyle style )
121 {
122   d->joinStyle = style;
123 }
124 
opacity() const125 double QgsTextMaskSettings::opacity() const
126 {
127   return d->opacity;
128 }
129 
setOpacity(double opacity)130 void QgsTextMaskSettings::setOpacity( double opacity )
131 {
132   d->opacity = opacity;
133 }
134 
paintEffect() const135 QgsPaintEffect *QgsTextMaskSettings::paintEffect() const
136 {
137   return d->paintEffect.get();
138 }
139 
setPaintEffect(QgsPaintEffect * effect)140 void QgsTextMaskSettings::setPaintEffect( QgsPaintEffect *effect )
141 {
142   d->paintEffect.reset( effect );
143 }
144 
updateDataDefinedProperties(QgsRenderContext & context,const QgsPropertyCollection & properties)145 void QgsTextMaskSettings::updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties )
146 {
147   if ( properties.isActive( QgsPalLayerSettings::MaskEnabled ) )
148   {
149     context.expressionContext().setOriginalValueVariable( d->enabled );
150     d->enabled = properties.valueAsBool( QgsPalLayerSettings::MaskEnabled, context.expressionContext(), d->enabled );
151   }
152 
153   if ( properties.isActive( QgsPalLayerSettings::MaskBufferSize ) )
154   {
155     context.expressionContext().setOriginalValueVariable( d->size );
156     d->size = properties.valueAsDouble( QgsPalLayerSettings::MaskBufferSize, context.expressionContext(), d->size );
157   }
158 
159   if ( properties.isActive( QgsPalLayerSettings::MaskBufferUnit ) )
160   {
161     QVariant exprVal = properties.value( QgsPalLayerSettings::MaskBufferUnit, context.expressionContext() );
162     if ( !exprVal.isNull() )
163     {
164       QString units = exprVal.toString();
165       if ( !units.isEmpty() )
166       {
167         bool ok;
168         QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
169         if ( ok )
170           d->sizeUnit = res;
171       }
172     }
173   }
174 
175   if ( properties.isActive( QgsPalLayerSettings::MaskOpacity ) )
176   {
177     context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
178     const QVariant val = properties.value( QgsPalLayerSettings::MaskOpacity, context.expressionContext(), d->opacity * 100 );
179     if ( !val.isNull() )
180     {
181       d->opacity = val.toDouble() / 100.0;
182     }
183   }
184 
185   if ( properties.isActive( QgsPalLayerSettings::MaskJoinStyle ) )
186   {
187     QVariant exprVal = properties.value( QgsPalLayerSettings::MaskJoinStyle, context.expressionContext() );
188     QString joinstr = exprVal.toString().trimmed();
189     if ( !joinstr.isEmpty() )
190     {
191       d->joinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( joinstr );
192     }
193   }
194 }
195 
referencedFields(const QgsRenderContext &) const196 QSet<QString> QgsTextMaskSettings::referencedFields( const QgsRenderContext & ) const
197 {
198   return QSet< QString >(); // nothing for now
199 }
200 
readXml(const QDomElement & elem)201 void QgsTextMaskSettings::readXml( const QDomElement &elem )
202 {
203   QDomElement textMaskElem = elem.firstChildElement( QStringLiteral( "text-mask" ) );
204   d->enabled = textMaskElem.attribute( QStringLiteral( "maskEnabled" ), QStringLiteral( "0" ) ).toInt();
205   d->type = static_cast<QgsTextMaskSettings::MaskType>( textMaskElem.attribute( QStringLiteral( "maskType" ), QStringLiteral( "0" ) ).toInt() );
206   d->size = textMaskElem.attribute( QStringLiteral( "maskSize" ), QStringLiteral( "0" ) ).toDouble();
207   d->sizeUnit = QgsUnitTypes::decodeRenderUnit( textMaskElem.attribute( QStringLiteral( "maskSizeUnits" ) ) );
208   d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( textMaskElem.attribute( QStringLiteral( "maskSizeMapUnitScale" ) ) );
209   d->joinStyle = static_cast< Qt::PenJoinStyle >( textMaskElem.attribute( QStringLiteral( "maskJoinStyle" ), QString::number( Qt::RoundJoin ) ).toUInt() );
210   d->opacity = textMaskElem.attribute( QStringLiteral( "maskOpacity" ), QStringLiteral( "1.0" ) ).toDouble();
211   QDomElement effectElem = textMaskElem.firstChildElement( QStringLiteral( "effect" ) );
212   if ( !effectElem.isNull() )
213     setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
214   else
215     setPaintEffect( nullptr );
216   d->maskedSymbolLayers = stringToSymbolLayerReferenceList( textMaskElem.attribute( QStringLiteral( "maskedSymbolLayers" ) ) );
217 }
218 
writeXml(QDomDocument & doc) const219 QDomElement QgsTextMaskSettings::writeXml( QDomDocument &doc ) const
220 {
221   QDomElement textMaskElem = doc.createElement( QStringLiteral( "text-mask" ) );
222   textMaskElem.setAttribute( QStringLiteral( "maskEnabled" ), d->enabled );
223   textMaskElem.setAttribute( QStringLiteral( "maskType" ), d->type );
224   textMaskElem.setAttribute( QStringLiteral( "maskSize" ), d->size );
225   textMaskElem.setAttribute( QStringLiteral( "maskSizeUnits" ), QgsUnitTypes::encodeUnit( d->sizeUnit ) );
226   textMaskElem.setAttribute( QStringLiteral( "maskSizeMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->sizeMapUnitScale ) );
227   textMaskElem.setAttribute( QStringLiteral( "maskJoinStyle" ), static_cast< unsigned int >( d->joinStyle ) );
228   textMaskElem.setAttribute( QStringLiteral( "maskOpacity" ), d->opacity );
229   if ( d->paintEffect && !QgsPaintEffectRegistry::isDefaultStack( d->paintEffect.get() ) )
230     d->paintEffect->saveProperties( doc, textMaskElem );
231   textMaskElem.setAttribute( QStringLiteral( "maskedSymbolLayers" ), symbolLayerReferenceListToString( d->maskedSymbolLayers ) );
232   return textMaskElem;
233 }
234 
maskedSymbolLayers() const235 QgsSymbolLayerReferenceList QgsTextMaskSettings::maskedSymbolLayers() const
236 {
237   return d->maskedSymbolLayers;
238 }
239 
setMaskedSymbolLayers(QgsSymbolLayerReferenceList maskedSymbols)240 void QgsTextMaskSettings::setMaskedSymbolLayers( QgsSymbolLayerReferenceList maskedSymbols )
241 {
242   d->maskedSymbolLayers = maskedSymbols;
243 }
244