Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsmasksymbollayer.cpp 3 : : --------------------- 4 : : begin : July 2019 5 : : copyright : (C) 2019 by Hugo Mercier 6 : : email : hugo dot mercier at oslandia 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 "qgsmasksymbollayer.h" 17 : : #include "qgssymbollayerutils.h" 18 : : #include "qgsproject.h" 19 : : #include "qgsvectorlayer.h" 20 : : #include "qgspainteffect.h" 21 : : #include "qgspainterswapper.h" 22 : : 23 : 0 : QgsMaskMarkerSymbolLayer::QgsMaskMarkerSymbolLayer() 24 : 0 : { 25 : 0 : mSymbol.reset( static_cast<QgsMarkerSymbol *>( QgsMarkerSymbol::createSimple( QVariantMap() ) ) ); 26 : 0 : } 27 : : 28 : 0 : bool QgsMaskMarkerSymbolLayer::setSubSymbol( QgsSymbol *symbol ) 29 : : { 30 : 0 : if ( symbol && symbol->type() == QgsSymbol::Marker ) 31 : : { 32 : 0 : mSymbol.reset( static_cast<QgsMarkerSymbol *>( symbol ) ); 33 : 0 : return true; 34 : : } 35 : 0 : delete symbol; 36 : 0 : return false; 37 : 0 : } 38 : : 39 : 0 : QgsSymbolLayer *QgsMaskMarkerSymbolLayer::create( const QVariantMap &props ) 40 : : { 41 : 0 : QgsMaskMarkerSymbolLayer *l = new QgsMaskMarkerSymbolLayer(); 42 : : 43 : 0 : l->setSubSymbol( QgsMarkerSymbol::createSimple( props ) ); 44 : : 45 : 0 : if ( props.contains( QStringLiteral( "mask_symbollayers" ) ) ) 46 : : { 47 : 0 : l->setMasks( stringToSymbolLayerReferenceList( props[QStringLiteral( "mask_symbollayers" )].toString() ) ); 48 : 0 : } 49 : 0 : return l; 50 : 0 : } 51 : : 52 : 0 : QgsMaskMarkerSymbolLayer *QgsMaskMarkerSymbolLayer::clone() const 53 : : { 54 : 0 : QgsMaskMarkerSymbolLayer *l = static_cast<QgsMaskMarkerSymbolLayer *>( create( properties() ) ); 55 : 0 : l->setSubSymbol( mSymbol->clone() ); 56 : 0 : l->setMasks( mMaskedSymbolLayers ); 57 : 0 : copyDataDefinedProperties( l ); 58 : 0 : copyPaintEffect( l ); 59 : 0 : return l; 60 : 0 : } 61 : : 62 : 0 : QString QgsMaskMarkerSymbolLayer::layerType() const 63 : : { 64 : 0 : return QStringLiteral( "MaskMarker" ); 65 : : } 66 : : 67 : 0 : QVariantMap QgsMaskMarkerSymbolLayer::properties() const 68 : : { 69 : 0 : QVariantMap props; 70 : 0 : props[QStringLiteral( "mask_symbollayers" )] = symbolLayerReferenceListToString( masks() ); 71 : 0 : return props; 72 : 0 : } 73 : : 74 : 0 : QSet<QString> QgsMaskMarkerSymbolLayer::usedAttributes( const QgsRenderContext &context ) const 75 : : { 76 : 0 : QSet<QString> attributes = QgsMarkerSymbolLayer::usedAttributes( context ); 77 : : 78 : 0 : attributes.unite( mSymbol->usedAttributes( context ) ); 79 : : 80 : 0 : return attributes; 81 : 0 : } 82 : : 83 : 0 : bool QgsMaskMarkerSymbolLayer::hasDataDefinedProperties() const 84 : : { 85 : 0 : if ( QgsSymbolLayer::hasDataDefinedProperties() ) 86 : 0 : return true; 87 : 0 : if ( mSymbol && mSymbol->hasDataDefinedProperties() ) 88 : 0 : return true; 89 : 0 : return false; 90 : 0 : } 91 : : 92 : 0 : void QgsMaskMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context ) 93 : : { 94 : : // since we need to swap the regular painter with the mask painter during rendering, 95 : : // effects won't work. So we cheat by handling effects ourselves in renderPoint 96 : 0 : if ( auto *lPaintEffect = paintEffect() ) 97 : : { 98 : 0 : mEffect.reset( lPaintEffect->clone() ); 99 : 0 : setPaintEffect( nullptr ); 100 : 0 : } 101 : 0 : mSymbol->startRender( context.renderContext() ); 102 : 0 : } 103 : : 104 : 0 : void QgsMaskMarkerSymbolLayer::stopRender( QgsSymbolRenderContext &context ) 105 : : { 106 : 0 : mSymbol->stopRender( context.renderContext() ); 107 : 0 : if ( mEffect ) 108 : : { 109 : 0 : setPaintEffect( mEffect.release() ); 110 : 0 : } 111 : 0 : } 112 : : 113 : 0 : void QgsMaskMarkerSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) 114 : : { 115 : 0 : QgsMarkerSymbolLayer::drawPreviewIcon( context, size ); 116 : 0 : } 117 : : 118 : 0 : QRectF QgsMaskMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context ) 119 : : { 120 : 0 : return mSymbol->bounds( point, context.renderContext() ); 121 : 0 : } 122 : : 123 : 0 : bool QgsMaskMarkerSymbolLayer::usesMapUnits() const 124 : : { 125 : 0 : return mSizeUnit == QgsUnitTypes::RenderMapUnits || mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits 126 : 0 : || ( mSymbol && mSymbol->usesMapUnits() ); 127 : : } 128 : : 129 : 0 : void QgsMaskMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext &context ) 130 : : { 131 : 0 : if ( !context.renderContext().painter() ) 132 : 0 : return; 133 : : 134 : 0 : if ( context.renderContext().isGuiPreview() ) 135 : : { 136 : 0 : mSymbol->renderPoint( point, context.feature(), context.renderContext(), /* layer = */ -1, /* selected = */ false ); 137 : 0 : return; 138 : : } 139 : : 140 : 0 : if ( ! context.renderContext().maskPainter() ) 141 : 0 : return; 142 : : 143 : 0 : if ( mMaskedSymbolLayers.isEmpty() ) 144 : 0 : return; 145 : : 146 : : { 147 : : // Otherwise switch to the mask painter before rendering 148 : 0 : QgsPainterSwapper swapper( context.renderContext(), context.renderContext().maskPainter() ); 149 : : 150 : : // Special case when an effect is defined on this mask symbol layer 151 : : // (effects defined on sub symbol's layers do not need special handling) 152 : 0 : if ( mEffect && mEffect->enabled() ) 153 : : { 154 : 0 : QgsEffectPainter p( context.renderContext() ); 155 : : // translate operates on the mask painter, which is what we want 156 : 0 : p->translate( point ); 157 : 0 : p.setEffect( mEffect.get() ); 158 : 0 : mSymbol->renderPoint( QPointF( 0, 0 ), context.feature(), context.renderContext(), /* layer = */ -1, /* selected = */ false ); 159 : : // the translation will be canceled at the end of scope here 160 : 0 : } 161 : : else 162 : : { 163 : 0 : mSymbol->renderPoint( point, context.feature(), context.renderContext(), /* layer = */ -1, /* selected = */ false ); 164 : : } 165 : 0 : } 166 : 0 : } 167 : : 168 : :