From 07b64a3f2d530ef6f444fecae8bab06f0173a7d8 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 9 Apr 2020 10:43:39 +1000 Subject: [PATCH] Add support for setting legend patch shapes for nodes in the layer tree --- .../layertree/qgslayertreelayer.sip.in | 18 ++++++++++++++ .../qgslayertreemodellegendnode.sip.in | 19 +++++++++++++++ src/core/layertree/qgslayertreelayer.cpp | 11 +++++++++ src/core/layertree/qgslayertreelayer.h | 19 +++++++++++++++ .../layertree/qgslayertreemodellegendnode.cpp | 22 +++++++++++++++-- .../layertree/qgslayertreemodellegendnode.h | 24 +++++++++++++++++++ src/core/qgslegendrenderer.cpp | 3 +++ 7 files changed, 114 insertions(+), 2 deletions(-) diff --git a/python/core/auto_generated/layertree/qgslayertreelayer.sip.in b/python/core/auto_generated/layertree/qgslayertreelayer.sip.in index 589f5da5068..863625fb514 100644 --- a/python/core/auto_generated/layertree/qgslayertreelayer.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreelayer.sip.in @@ -136,6 +136,24 @@ set the expression to evaluate Returns the expression member of the LayerTreeNode .. versionadded:: 3.10 +%End + + QgsLegendPatchShape patchShape() const; +%Docstring +Returns the symbol patch shape to use when rendering the legend node symbol. + +.. seealso:: :py:func:`setPatchShape` + +.. versionadded:: 3.14 +%End + + void setPatchShape( const QgsLegendPatchShape &shape ); +%Docstring +Sets the symbol patch ``shape`` to use when rendering the legend node symbol. + +.. seealso:: :py:func:`patchShape` + +.. versionadded:: 3.14 %End signals: diff --git a/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in b/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in index 0a54f85db4f..ca0ccc71f44 100644 --- a/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in @@ -99,6 +99,7 @@ Default implementation does nothing. * double maxSiblingSymbolWidth; + QgsLegendPatchShape patchShape; }; struct ItemMetrics @@ -322,6 +323,24 @@ Sets format of text to be shown on top of the symbol. Label of the symbol, user defined label will be used, otherwise will default to the label made by QGIS. .. versionadded:: 3.10 +%End + + QgsLegendPatchShape patchShape() const; +%Docstring +Returns the symbol patch shape to use when rendering the legend node symbol. + +.. seealso:: :py:func:`setPatchShape` + +.. versionadded:: 3.14 +%End + + void setPatchShape( const QgsLegendPatchShape &shape ); +%Docstring +Sets the symbol patch ``shape`` to use when rendering the legend node symbol. + +.. seealso:: :py:func:`patchShape` + +.. versionadded:: 3.14 %End QString evaluateLabel( const QgsExpressionContext &context = QgsExpressionContext(), const QString &label = QString() ); diff --git a/src/core/layertree/qgslayertreelayer.cpp b/src/core/layertree/qgslayertreelayer.cpp index 6d75202a3a5..8335b9dda97 100644 --- a/src/core/layertree/qgslayertreelayer.cpp +++ b/src/core/layertree/qgslayertreelayer.cpp @@ -39,6 +39,7 @@ QgsLayerTreeLayer::QgsLayerTreeLayer( const QgsLayerTreeLayer &other ) : QgsLayerTreeNode( other ) , mRef( other.mRef ) , mLayerName( other.mLayerName ) + , mPatchShape( other.mPatchShape ) { attachToLayer(); } @@ -196,3 +197,13 @@ void QgsLayerTreeLayer::setLabelExpression( const QString &expression ) mLabelExpression = expression; } +QgsLegendPatchShape QgsLayerTreeLayer::patchShape() const +{ + return mPatchShape; +} + +void QgsLayerTreeLayer::setPatchShape( const QgsLegendPatchShape &shape ) +{ + mPatchShape = shape; +} + diff --git a/src/core/layertree/qgslayertreelayer.h b/src/core/layertree/qgslayertreelayer.h index d4186228269..a723ad808b8 100644 --- a/src/core/layertree/qgslayertreelayer.h +++ b/src/core/layertree/qgslayertreelayer.h @@ -21,6 +21,7 @@ #include "qgslayertreenode.h" #include "qgsmaplayerref.h" #include "qgsreadwritecontext.h" +#include "qgslegendpatchshape.h" class QgsMapLayer; @@ -142,6 +143,22 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode */ QString labelExpression() const { return mLabelExpression; } + /** + * Returns the symbol patch shape to use when rendering the legend node symbol. + * + * \see setPatchShape() + * \since QGIS 3.14 + */ + QgsLegendPatchShape patchShape() const; + + /** + * Sets the symbol patch \a shape to use when rendering the legend node symbol. + * + * \see patchShape() + * \since QGIS 3.14 + */ + void setPatchShape( const QgsLegendPatchShape &shape ); + signals: /** @@ -191,6 +208,8 @@ class CORE_EXPORT QgsLayerTreeLayer : public QgsLayerTreeNode */ QgsLayerTreeLayer( const QgsLayerTreeLayer &other ); #endif + + QgsLegendPatchShape mPatchShape; }; diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index 2153765031d..3bdecaa534b 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -303,6 +303,23 @@ QString QgsSymbolLegendNode::symbolLabel() const return label; } +QgsLegendPatchShape QgsSymbolLegendNode::patchShape() const +{ + if ( mEmbeddedInParent ) + { + return mLayerNode->patchShape(); + } + else + { + return mPatchShape; + } +} + +void QgsSymbolLegendNode::setPatchShape( const QgsLegendPatchShape &shape ) +{ + mPatchShape = shape; +} + void QgsSymbolLegendNode::setSymbol( QgsSymbol *symbol ) { if ( !symbol ) @@ -493,6 +510,7 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC // setup temporary render context QgsRenderContext *context = nullptr; std::unique_ptr< QgsRenderContext > tempRenderContext; + QgsLegendPatchShape patchShape = ctx ? ctx->patchShape : QgsLegendPatchShape(); if ( ctx && ctx->context ) context = ctx->context; else @@ -577,7 +595,7 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC imagePainter.setRenderHint( QPainter::Antialiasing ); context->setPainter( &imagePainter ); imagePainter.translate( maxBleed, maxBleed ); - s->drawPreviewIcon( &imagePainter, symbolSize, context ); + s->drawPreviewIcon( &imagePainter, symbolSize, context, false, nullptr, &patchShape ); imagePainter.translate( -maxBleed, -maxBleed ); context->setPainter( ctx->painter ); //reduce opacity of image @@ -589,7 +607,7 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC } else { - s->drawPreviewIcon( p, QSize( static_cast< int >( std::round( width * dotsPerMM ) ), static_cast< int >( std::round( height * dotsPerMM ) ) ), context ); + s->drawPreviewIcon( p, QSize( static_cast< int >( std::round( width * dotsPerMM ) ), static_cast< int >( std::round( height * dotsPerMM ) ) ), context, false, nullptr, &patchShape ); } if ( !mTextOnSymbolLabel.isEmpty() ) diff --git a/src/core/layertree/qgslayertreemodellegendnode.h b/src/core/layertree/qgslayertreemodellegendnode.h index 32a05931e7b..589956200c0 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.h +++ b/src/core/layertree/qgslayertreemodellegendnode.h @@ -28,6 +28,7 @@ #include "qgsrasterdataprovider.h" // for QgsImageFetcher dtor visibility #include "qgsexpressioncontext.h" +#include "qgslegendpatchshape.h" class QgsLayerTreeLayer; class QgsLayerTreeModel; @@ -145,6 +146,12 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject */ double maxSiblingSymbolWidth = 0.0; + /** + * The patch shape to render for the node. + * + * \since QGIS 3.14 + */ + QgsLegendPatchShape patchShape; }; struct ItemMetrics @@ -221,6 +228,7 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject QgsLayerTreeLayer *mLayerNode = nullptr; bool mEmbeddedInParent; QString mUserLabel; + QgsLegendPatchShape mPatchShape; }; #include "qgslegendsymbolitem.h" @@ -335,6 +343,22 @@ class CORE_EXPORT QgsSymbolLegendNode : public QgsLayerTreeModelLegendNode */ QString symbolLabel() const; + /** + * Returns the symbol patch shape to use when rendering the legend node symbol. + * + * \see setPatchShape() + * \since QGIS 3.14 + */ + QgsLegendPatchShape patchShape() const; + + /** + * Sets the symbol patch \a shape to use when rendering the legend node symbol. + * + * \see patchShape() + * \since QGIS 3.14 + */ + void setPatchShape( const QgsLegendPatchShape &shape ); + /** * Evaluates and returns the text label of the current node * \param context extra QgsExpressionContext to use for evaluating the expression diff --git a/src/core/qgslegendrenderer.cpp b/src/core/qgslegendrenderer.cpp index 053c0837f1c..7b81d4be55d 100644 --- a/src/core/qgslegendrenderer.cpp +++ b/src/core/qgslegendrenderer.cpp @@ -651,6 +651,9 @@ QgsLegendRenderer::LegendComponent QgsLegendRenderer::drawSymbolItemInternal( Qg ctx.columnRight = columnContext.right; ctx.maxSiblingSymbolWidth = maxSiblingSymbolWidth; + if ( const QgsSymbolLegendNode *symbolNode = dynamic_cast< const QgsSymbolLegendNode * >( symbolItem ) ) + ctx.patchShape = symbolNode->patchShape(); + QgsLayerTreeModelLegendNode::ItemMetrics im = symbolItem->draw( mSettings, context ? &ctx : ( painter ? &ctx : nullptr ) );