Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgstextbuffersettings.cpp 3 : : ----------------- 4 : : begin : May 2020 5 : : copyright : (C) Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : 8 : : *************************************************************************** 9 : : * * 10 : : * This program is free software; you can redistribute it and/or modify * 11 : : * it under the terms of the GNU General Public License as published by * 12 : : * the Free Software Foundation; either version 2 of the License, or * 13 : : * (at your option) any later version. * 14 : : * * 15 : : ***************************************************************************/ 16 : : 17 : : #include "qgstextbuffersettings.h" 18 : : #include "qgstextrenderer_p.h" 19 : : #include "qgsvectorlayer.h" 20 : : #include "qgspallabeling.h" 21 : : #include "qgssymbollayerutils.h" 22 : : #include "qgspainting.h" 23 : : #include "qgspainteffectregistry.h" 24 : : #include "qgstextrendererutils.h" 25 : : 26 : 78 : QgsTextBufferSettings::QgsTextBufferSettings() 27 : : { 28 : 78 : d = new QgsTextBufferSettingsPrivate(); 29 : 78 : } 30 : : 31 : 0 : QgsTextBufferSettings::QgsTextBufferSettings( const QgsTextBufferSettings &other ) //NOLINT 32 : 0 : : d( other.d ) 33 : : { 34 : 0 : } 35 : : 36 : 0 : QgsTextBufferSettings &QgsTextBufferSettings::operator=( const QgsTextBufferSettings &other ) //NOLINT 37 : : { 38 : 0 : d = other.d; 39 : 0 : return *this; 40 : : } 41 : : 42 : 62 : QgsTextBufferSettings::~QgsTextBufferSettings() //NOLINT 43 : : { 44 : : 45 : 62 : } 46 : : 47 : 0 : bool QgsTextBufferSettings::operator==( const QgsTextBufferSettings &other ) const 48 : : { 49 : 0 : if ( d->enabled != other.enabled() 50 : 0 : || d->size != other.size() 51 : 0 : || d->sizeUnit != other.sizeUnit() 52 : 0 : || d->sizeMapUnitScale != other.sizeMapUnitScale() 53 : 0 : || d->color != other.color() 54 : 0 : || d->opacity != other.opacity() 55 : 0 : || d->fillBufferInterior != other.fillBufferInterior() 56 : 0 : || d->joinStyle != other.joinStyle() 57 : 0 : || d->blendMode != other.blendMode() ) 58 : 0 : return false; 59 : : 60 : 0 : if ( static_cast< bool >( d->paintEffect ) != static_cast< bool >( other.paintEffect() ) 61 : 0 : || ( d->paintEffect && d->paintEffect->properties() != other.paintEffect()->properties() ) ) 62 : 0 : return false; 63 : : 64 : 0 : return true; 65 : 0 : } 66 : : 67 : 0 : bool QgsTextBufferSettings::operator!=( const QgsTextBufferSettings &other ) const 68 : : { 69 : 0 : return !( *this == other ); 70 : : } 71 : : 72 : 0 : bool QgsTextBufferSettings::enabled() const 73 : : { 74 : 0 : return d->enabled; 75 : : } 76 : : 77 : 0 : void QgsTextBufferSettings::setEnabled( bool enabled ) 78 : : { 79 : 0 : d->enabled = enabled; 80 : 0 : } 81 : : 82 : 0 : double QgsTextBufferSettings::size() const 83 : : { 84 : 0 : return d->size; 85 : : } 86 : : 87 : 0 : void QgsTextBufferSettings::setSize( double size ) 88 : : { 89 : 0 : d->size = size; 90 : 0 : } 91 : : 92 : 0 : QgsUnitTypes::RenderUnit QgsTextBufferSettings::sizeUnit() const 93 : : { 94 : 0 : return d->sizeUnit; 95 : : } 96 : : 97 : 0 : void QgsTextBufferSettings::setSizeUnit( QgsUnitTypes::RenderUnit unit ) 98 : : { 99 : 0 : d->sizeUnit = unit; 100 : 0 : } 101 : : 102 : 0 : QgsMapUnitScale QgsTextBufferSettings::sizeMapUnitScale() const 103 : : { 104 : 0 : return d->sizeMapUnitScale; 105 : : } 106 : : 107 : 0 : void QgsTextBufferSettings::setSizeMapUnitScale( const QgsMapUnitScale &scale ) 108 : : { 109 : 0 : d->sizeMapUnitScale = scale; 110 : 0 : } 111 : : 112 : 0 : QColor QgsTextBufferSettings::color() const 113 : : { 114 : 0 : return d->color; 115 : : } 116 : : 117 : 0 : void QgsTextBufferSettings::setColor( const QColor &color ) 118 : : { 119 : 0 : d->color = color; 120 : 0 : } 121 : : 122 : 0 : bool QgsTextBufferSettings::fillBufferInterior() const 123 : : { 124 : 0 : return d->fillBufferInterior; 125 : : } 126 : : 127 : 0 : void QgsTextBufferSettings::setFillBufferInterior( bool fill ) 128 : : { 129 : 0 : d->fillBufferInterior = fill; 130 : 0 : } 131 : : 132 : 0 : double QgsTextBufferSettings::opacity() const 133 : : { 134 : 0 : return d->opacity; 135 : : } 136 : : 137 : 0 : void QgsTextBufferSettings::setOpacity( double opacity ) 138 : : { 139 : 0 : d->opacity = opacity; 140 : 0 : } 141 : : 142 : 0 : Qt::PenJoinStyle QgsTextBufferSettings::joinStyle() const 143 : : { 144 : 0 : return d->joinStyle; 145 : : } 146 : : 147 : 0 : void QgsTextBufferSettings::setJoinStyle( Qt::PenJoinStyle style ) 148 : : { 149 : 0 : d->joinStyle = style; 150 : 0 : } 151 : : 152 : 0 : QPainter::CompositionMode QgsTextBufferSettings::blendMode() const 153 : : { 154 : 0 : return d->blendMode; 155 : : } 156 : : 157 : 0 : void QgsTextBufferSettings::setBlendMode( QPainter::CompositionMode mode ) 158 : : { 159 : 0 : d->blendMode = mode; 160 : 0 : } 161 : : 162 : 0 : const QgsPaintEffect *QgsTextBufferSettings::paintEffect() const 163 : : { 164 : 0 : return d->paintEffect.get(); 165 : : } 166 : : 167 : 0 : void QgsTextBufferSettings::setPaintEffect( QgsPaintEffect *effect ) 168 : : { 169 : 0 : d->paintEffect.reset( effect ); 170 : 0 : } 171 : : 172 : 0 : void QgsTextBufferSettings::updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties ) 173 : : { 174 : 0 : if ( properties.isActive( QgsPalLayerSettings::BufferDraw ) ) 175 : : { 176 : 0 : context.expressionContext().setOriginalValueVariable( d->enabled ); 177 : 0 : d->enabled = properties.valueAsBool( QgsPalLayerSettings::BufferDraw, context.expressionContext(), d->enabled ); 178 : 0 : } 179 : : 180 : 0 : if ( properties.isActive( QgsPalLayerSettings::BufferSize ) ) 181 : : { 182 : 0 : context.expressionContext().setOriginalValueVariable( d->size ); 183 : 0 : d->size = properties.valueAsDouble( QgsPalLayerSettings::BufferSize, context.expressionContext(), d->size ); 184 : 0 : } 185 : : 186 : 0 : QVariant exprVal = properties.value( QgsPalLayerSettings::BufferUnit, context.expressionContext() ); 187 : 0 : if ( exprVal.isValid() ) 188 : : { 189 : 0 : QString units = exprVal.toString(); 190 : 0 : if ( !units.isEmpty() ) 191 : : { 192 : : bool ok; 193 : 0 : QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok ); 194 : 0 : if ( ok ) 195 : 0 : d->sizeUnit = res; 196 : 0 : } 197 : 0 : } 198 : : 199 : 0 : if ( properties.isActive( QgsPalLayerSettings::BufferOpacity ) ) 200 : : { 201 : 0 : context.expressionContext().setOriginalValueVariable( d->opacity * 100 ); 202 : 0 : d->opacity = properties.value( QgsPalLayerSettings::BufferOpacity, context.expressionContext(), d->opacity * 100 ).toDouble() / 100.0; 203 : 0 : } 204 : : 205 : 0 : if ( properties.isActive( QgsPalLayerSettings::BufferColor ) ) 206 : : { 207 : 0 : context.expressionContext().setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( d->color ) ); 208 : 0 : d->color = properties.valueAsColor( QgsPalLayerSettings::BufferColor, context.expressionContext(), d->color ); 209 : 0 : } 210 : : 211 : 0 : if ( properties.isActive( QgsPalLayerSettings::BufferBlendMode ) ) 212 : : { 213 : 0 : exprVal = properties.value( QgsPalLayerSettings::BufferBlendMode, context.expressionContext() ); 214 : 0 : QString blendstr = exprVal.toString().trimmed(); 215 : 0 : if ( !blendstr.isEmpty() ) 216 : 0 : d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr ); 217 : 0 : } 218 : : 219 : 0 : if ( properties.isActive( QgsPalLayerSettings::BufferJoinStyle ) ) 220 : : { 221 : 0 : exprVal = properties.value( QgsPalLayerSettings::BufferJoinStyle, context.expressionContext() ); 222 : 0 : QString joinstr = exprVal.toString().trimmed(); 223 : 0 : if ( !joinstr.isEmpty() ) 224 : : { 225 : 0 : d->joinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( joinstr ); 226 : 0 : } 227 : 0 : } 228 : 0 : } 229 : : 230 : 0 : QSet<QString> QgsTextBufferSettings::referencedFields( const QgsRenderContext & ) const 231 : : { 232 : 0 : return QSet< QString >(); // nothing for now 233 : : } 234 : : 235 : 0 : void QgsTextBufferSettings::readFromLayer( QgsVectorLayer *layer ) 236 : : { 237 : : // text buffer 238 : 0 : double bufSize = layer->customProperty( QStringLiteral( "labeling/bufferSize" ), QVariant( 0.0 ) ).toDouble(); 239 : : 240 : : // fix for buffer being keyed off of just its size in the past (<2.0) 241 : 0 : QVariant drawBuffer = layer->customProperty( QStringLiteral( "labeling/bufferDraw" ), QVariant() ); 242 : 0 : if ( drawBuffer.isValid() ) 243 : : { 244 : 0 : d->enabled = drawBuffer.toBool(); 245 : 0 : d->size = bufSize; 246 : 0 : } 247 : 0 : else if ( bufSize != 0.0 ) 248 : : { 249 : 0 : d->enabled = true; 250 : 0 : d->size = bufSize; 251 : 0 : } 252 : : else 253 : : { 254 : : // keep bufferSize at new 1.0 default 255 : 0 : d->enabled = false; 256 : : } 257 : : 258 : 0 : if ( layer->customProperty( QStringLiteral( "labeling/bufferSizeUnits" ) ).toString().isEmpty() ) 259 : : { 260 : 0 : bool bufferSizeInMapUnits = layer->customProperty( QStringLiteral( "labeling/bufferSizeInMapUnits" ) ).toBool(); 261 : 0 : d->sizeUnit = bufferSizeInMapUnits ? QgsUnitTypes::RenderMapUnits : QgsUnitTypes::RenderMillimeters; 262 : 0 : } 263 : : else 264 : : { 265 : 0 : d->sizeUnit = QgsUnitTypes::decodeRenderUnit( layer->customProperty( QStringLiteral( "labeling/bufferSizeUnits" ) ).toString() ); 266 : : } 267 : : 268 : 0 : if ( layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitScale" ) ).toString().isEmpty() ) 269 : : { 270 : : //fallback to older property 271 : 0 : double oldMin = layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitMinScale" ), 0.0 ).toDouble(); 272 : 0 : d->sizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0; 273 : 0 : double oldMax = layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitMaxScale" ), 0.0 ).toDouble(); 274 : 0 : d->sizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0; 275 : 0 : } 276 : : else 277 : : { 278 : 0 : d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/bufferSizeMapUnitScale" ) ).toString() ); 279 : : } 280 : 0 : d->color = QgsTextRendererUtils::readColor( layer, QStringLiteral( "labeling/bufferColor" ), Qt::white, false ); 281 : 0 : if ( layer->customProperty( QStringLiteral( "labeling/bufferOpacity" ) ).toString().isEmpty() ) 282 : : { 283 : 0 : d->opacity = ( 1 - layer->customProperty( QStringLiteral( "labeling/bufferTransp" ) ).toInt() / 100.0 ); //0 -100 284 : 0 : } 285 : : else 286 : : { 287 : 0 : d->opacity = ( layer->customProperty( QStringLiteral( "labeling/bufferOpacity" ) ).toDouble() ); 288 : : } 289 : 0 : d->blendMode = QgsPainting::getCompositionMode( 290 : 0 : static_cast< QgsPainting::BlendMode >( layer->customProperty( QStringLiteral( "labeling/bufferBlendMode" ), QVariant( QgsPainting::BlendNormal ) ).toUInt() ) ); 291 : 0 : d->joinStyle = static_cast< Qt::PenJoinStyle >( layer->customProperty( QStringLiteral( "labeling/bufferJoinStyle" ), QVariant( Qt::RoundJoin ) ).toUInt() ); 292 : : 293 : 0 : d->fillBufferInterior = !layer->customProperty( QStringLiteral( "labeling/bufferNoFill" ), QVariant( false ) ).toBool(); 294 : : 295 : 0 : if ( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).isValid() ) 296 : : { 297 : 0 : QDomDocument doc( QStringLiteral( "effect" ) ); 298 : 0 : doc.setContent( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).toString() ); 299 : 0 : QDomElement effectElem = doc.firstChildElement( QStringLiteral( "effect" ) ).firstChildElement( QStringLiteral( "effect" ) ); 300 : 0 : setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) ); 301 : 0 : } 302 : : else 303 : 0 : setPaintEffect( nullptr ); 304 : 0 : } 305 : : 306 : 0 : void QgsTextBufferSettings::readXml( const QDomElement &elem ) 307 : : { 308 : 0 : QDomElement textBufferElem = elem.firstChildElement( QStringLiteral( "text-buffer" ) ); 309 : 0 : double bufSize = textBufferElem.attribute( QStringLiteral( "bufferSize" ), QStringLiteral( "0" ) ).toDouble(); 310 : : 311 : : // fix for buffer being keyed off of just its size in the past (<2.0) 312 : 0 : QVariant drawBuffer = textBufferElem.attribute( QStringLiteral( "bufferDraw" ) ); 313 : 0 : if ( drawBuffer.isValid() ) 314 : : { 315 : 0 : d->enabled = drawBuffer.toBool(); 316 : 0 : d->size = bufSize; 317 : 0 : } 318 : 0 : else if ( bufSize != 0.0 ) 319 : : { 320 : 0 : d->enabled = true; 321 : 0 : d->size = bufSize; 322 : 0 : } 323 : : else 324 : : { 325 : : // keep bufferSize at new 1.0 default 326 : 0 : d->enabled = false; 327 : : } 328 : : 329 : 0 : if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferSizeUnits" ) ) ) 330 : : { 331 : 0 : bool bufferSizeInMapUnits = textBufferElem.attribute( QStringLiteral( "bufferSizeInMapUnits" ) ).toInt(); 332 : 0 : d->sizeUnit = bufferSizeInMapUnits ? QgsUnitTypes::RenderMapUnits : QgsUnitTypes::RenderMillimeters; 333 : 0 : } 334 : : else 335 : : { 336 : 0 : d->sizeUnit = QgsUnitTypes::decodeRenderUnit( textBufferElem.attribute( QStringLiteral( "bufferSizeUnits" ) ) ); 337 : : } 338 : : 339 : 0 : if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferSizeMapUnitScale" ) ) ) 340 : : { 341 : : //fallback to older property 342 : 0 : double oldMin = textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble(); 343 : 0 : d->sizeMapUnitScale.minScale = oldMin != 0 ? 1.0 / oldMin : 0; 344 : 0 : double oldMax = textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble(); 345 : 0 : d->sizeMapUnitScale.maxScale = oldMax != 0 ? 1.0 / oldMax : 0; 346 : 0 : } 347 : : else 348 : : { 349 : 0 : d->sizeMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( textBufferElem.attribute( QStringLiteral( "bufferSizeMapUnitScale" ) ) ); 350 : : } 351 : 0 : d->color = QgsSymbolLayerUtils::decodeColor( textBufferElem.attribute( QStringLiteral( "bufferColor" ), QgsSymbolLayerUtils::encodeColor( Qt::white ) ) ); 352 : : 353 : 0 : if ( !textBufferElem.hasAttribute( QStringLiteral( "bufferOpacity" ) ) ) 354 : : { 355 : 0 : d->opacity = ( 1 - textBufferElem.attribute( QStringLiteral( "bufferTransp" ) ).toInt() / 100.0 ); //0 -100 356 : 0 : } 357 : : else 358 : : { 359 : 0 : d->opacity = ( textBufferElem.attribute( QStringLiteral( "bufferOpacity" ) ).toDouble() ); 360 : : } 361 : : 362 : 0 : d->blendMode = QgsPainting::getCompositionMode( 363 : 0 : static_cast< QgsPainting::BlendMode >( textBufferElem.attribute( QStringLiteral( "bufferBlendMode" ), QString::number( QgsPainting::BlendNormal ) ).toUInt() ) ); 364 : 0 : d->joinStyle = static_cast< Qt::PenJoinStyle >( textBufferElem.attribute( QStringLiteral( "bufferJoinStyle" ), QString::number( Qt::RoundJoin ) ).toUInt() ); 365 : 0 : d->fillBufferInterior = !textBufferElem.attribute( QStringLiteral( "bufferNoFill" ), QStringLiteral( "0" ) ).toInt(); 366 : 0 : QDomElement effectElem = textBufferElem.firstChildElement( QStringLiteral( "effect" ) ); 367 : 0 : if ( !effectElem.isNull() ) 368 : 0 : setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) ); 369 : : else 370 : 0 : setPaintEffect( nullptr ); 371 : 0 : } 372 : : 373 : 0 : QDomElement QgsTextBufferSettings::writeXml( QDomDocument &doc ) const 374 : : { 375 : : // text buffer 376 : 0 : QDomElement textBufferElem = doc.createElement( QStringLiteral( "text-buffer" ) ); 377 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferDraw" ), d->enabled ); 378 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferSize" ), d->size ); 379 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferSizeUnits" ), QgsUnitTypes::encodeUnit( d->sizeUnit ) ); 380 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferSizeMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( d->sizeMapUnitScale ) ); 381 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferColor" ), QgsSymbolLayerUtils::encodeColor( d->color ) ); 382 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferNoFill" ), !d->fillBufferInterior ); 383 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferOpacity" ), d->opacity ); 384 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferJoinStyle" ), static_cast< unsigned int >( d->joinStyle ) ); 385 : 0 : textBufferElem.setAttribute( QStringLiteral( "bufferBlendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) ); 386 : 0 : if ( d->paintEffect && !QgsPaintEffectRegistry::isDefaultStack( d->paintEffect.get() ) ) 387 : 0 : d->paintEffect->saveProperties( doc, textBufferElem ); 388 : 0 : return textBufferElem; 389 : 0 : }