Skip to content

Commit e8ec004

Browse files
committedNov 24, 2019
[FEATURE][diagrams] Paint effect support for diagram renderer
Allows for diagrams to use paint effects, including drop shadows, outer glows, etc... Sponsored by SLYR
1 parent 204bd47 commit e8ec004

File tree

8 files changed

+265
-121
lines changed

8 files changed

+265
-121
lines changed
 

‎python/core/auto_generated/qgsdiagramrenderer.sip.in

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ QgsDiagramLayerSettings stores settings which control how ALL diagrams within a
376376
%Docstring
377377
Constructor for QgsDiagramSettings
378378
%End
379+
~QgsDiagramSettings();
379380

380381
QgsDiagramSettings( const QgsDiagramSettings &other );
381382
%Docstring
@@ -582,6 +583,26 @@ Sets whether the diagram axis should be shown.
582583

583584
.. seealso:: :py:func:`setAxisLineSymbol`
584585

586+
.. versionadded:: 3.12
587+
%End
588+
589+
QgsPaintEffect *paintEffect() const;
590+
%Docstring
591+
Returns the paint effect to use while rendering diagrams.
592+
593+
.. seealso:: :py:func:`setPaintEffect`
594+
595+
.. versionadded:: 3.12
596+
%End
597+
598+
void setPaintEffect( QgsPaintEffect *effect /Transfer/ );
599+
%Docstring
600+
Sets the paint ``effect`` to use while rendering diagrams.
601+
602+
Ownership of ``effect`` is transferred to the settings.
603+
604+
.. seealso:: :py:func:`paintEffect`
605+
585606
.. versionadded:: 3.12
586607
%End
587608

‎src/app/qgsdiagramproperties.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "qgsauxiliarystorage.h"
4545
#include "qgsexpressioncontextutils.h"
4646
#include "qgspropertytransformer.h"
47+
#include "qgspainteffectregistry.h"
4748

4849
#include <QList>
4950
#include <QMessageBox>
@@ -238,6 +239,8 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
238239
newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
239240
}
240241

242+
mPaintEffect.reset( QgsPaintEffectRegistry::defaultStack() );
243+
241244
const QgsDiagramRenderer *dr = layer->diagramRenderer();
242245
if ( !dr ) //no diagram renderer yet, insert reasonable default
243246
{
@@ -284,6 +287,7 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
284287
mBackgroundColorButton->setColor( QColor( 255, 255, 255, 255 ) );
285288
//force a refresh of widget status to match diagram type
286289
mDiagramTypeComboBox_currentIndexChanged( mDiagramTypeComboBox->currentIndex() );
290+
287291
}
288292
else // already a diagram renderer present
289293
{
@@ -329,6 +333,9 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
329333
mLabelPlacementComboBox->setCurrentIndex( 1 );
330334
}
331335

336+
if ( settingList.at( 0 ).paintEffect() )
337+
mPaintEffect.reset( settingList.at( 0 ).paintEffect()->clone() );
338+
332339
mAngleOffsetComboBox->setCurrentIndex( mAngleOffsetComboBox->findData( settingList.at( 0 ).rotationOffset ) );
333340
mAngleDirectionComboBox->setCurrentIndex( mAngleDirectionComboBox->findData( settingList.at( 0 ).direction() ) );
334341

@@ -483,6 +490,7 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
483490
}
484491
}
485492
}
493+
mPaintEffectWidget->setPaintEffect( mPaintEffect.get() );
486494

487495
connect( mAddAttributeExpression, &QPushButton::clicked, this, &QgsDiagramProperties::showAddAttributeExpressionDialog );
488496
registerDataDefinedButton( mBackgroundColorDDBtn, QgsDiagramLayerSettings::BackgroundColor );
@@ -841,6 +849,11 @@ void QgsDiagramProperties::apply()
841849
ds.setSpacingUnit( mBarSpacingUnitComboBox->unit() );
842850
ds.setSpacingMapUnitScale( mBarSpacingUnitComboBox->getMapUnitScale() );
843851

852+
if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect.get() ) )
853+
ds.setPaintEffect( mPaintEffect->clone() );
854+
else
855+
ds.setPaintEffect( nullptr );
856+
844857
QgsDiagramRenderer *renderer = nullptr;
845858
if ( mFixedSizeRadio->isChecked() )
846859
{

‎src/app/qgsdiagramproperties.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class APP_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr
6868
//! Polygon placement button group
6969
QButtonGroup *mPlacePolygonBtnGrp = nullptr;
7070

71+
std::unique_ptr< QgsPaintEffect> mPaintEffect;
72+
7173
enum Columns
7274
{
7375
ColumnAttributeExpression = 0,

‎src/core/qgsdiagramrenderer.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
#include "qgslayertreemodellegendnode.h"
2525
#include "qgsfontutils.h"
2626
#include "qgssymbollayerutils.h"
27+
#include "qgspainteffectregistry.h"
28+
#include "qgspainteffect.h"
29+
#include "qgsapplication.h"
2730

2831
#include <QDomElement>
2932
#include <QPainter>
@@ -330,6 +333,12 @@ void QgsDiagramSettings::readXml( const QDomElement &elem, const QgsReadWriteCon
330333
categoryLabels.append( *catIt );
331334
}
332335
}
336+
337+
QDomElement effectElem = elem.firstChildElement( QStringLiteral( "effect" ) );
338+
if ( !effectElem.isNull() )
339+
setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
340+
else
341+
setPaintEffect( QgsApplication::paintEffectRegistry()->defaultStack() );
333342
}
334343

335344
void QgsDiagramSettings::writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
@@ -398,10 +407,6 @@ void QgsDiagramSettings::writeXml( QDomElement &rendererElem, QDomDocument &doc,
398407
case Up:
399408
categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Up" ) );
400409
break;
401-
402-
default:
403-
categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Up" ) );
404-
break;
405410
}
406411

407412
categoryElem.setAttribute( QStringLiteral( "barWidth" ), QString::number( barWidth ) );
@@ -425,6 +430,9 @@ void QgsDiagramSettings::writeXml( QDomElement &rendererElem, QDomDocument &doc,
425430
axisSymbolElem.appendChild( symbolElem );
426431
categoryElem.appendChild( axisSymbolElem );
427432

433+
if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect.get() ) )
434+
mPaintEffect->saveProperties( doc, categoryElem );
435+
428436
rendererElem.appendChild( categoryElem );
429437
}
430438

@@ -474,6 +482,13 @@ void QgsDiagramRenderer::renderDiagram( const QgsFeature &feature, QgsRenderCont
474482
s.rotationOffset = properties.valueAsDouble( QgsDiagramLayerSettings::StartAngle, c.expressionContext(), s.rotationOffset );
475483
}
476484

485+
QgsPaintEffect *effect = s.paintEffect();
486+
std::unique_ptr< QgsEffectPainter > effectPainter;
487+
if ( effect && effect->enabled() )
488+
{
489+
effectPainter = qgis::make_unique< QgsEffectPainter >( c, effect );
490+
}
491+
477492
mDiagram->renderDiagram( feature, c, s, pos );
478493
}
479494

@@ -807,11 +822,24 @@ void QgsDiagramSettings::setShowAxis( bool showAxis )
807822
mShowAxis = showAxis;
808823
}
809824

825+
QgsPaintEffect *QgsDiagramSettings::paintEffect() const
826+
{
827+
return mPaintEffect.get();
828+
}
829+
830+
void QgsDiagramSettings::setPaintEffect( QgsPaintEffect *effect )
831+
{
832+
if ( effect != mPaintEffect.get() )
833+
mPaintEffect.reset( effect );
834+
}
835+
810836
QgsDiagramSettings::QgsDiagramSettings()
811837
: mAxisLineSymbol( qgis::make_unique< QgsLineSymbol >() )
812838
{
813839
}
814840

841+
QgsDiagramSettings::~QgsDiagramSettings() = default;
842+
815843
QgsDiagramSettings::QgsDiagramSettings( const QgsDiagramSettings &other )
816844
: enabled( other.enabled )
817845
, font( other.font )
@@ -842,6 +870,7 @@ QgsDiagramSettings::QgsDiagramSettings( const QgsDiagramSettings &other )
842870
, mDirection( other.mDirection )
843871
, mShowAxis( other.mShowAxis )
844872
, mAxisLineSymbol( other.mAxisLineSymbol ? other.mAxisLineSymbol->clone() : nullptr )
873+
, mPaintEffect( other.mPaintEffect ? other.mPaintEffect->clone() : nullptr )
845874
{
846875

847876
}
@@ -877,6 +906,7 @@ QgsDiagramSettings &QgsDiagramSettings::operator=( const QgsDiagramSettings &oth
877906
mDirection = other.mDirection;
878907
mAxisLineSymbol.reset( other.mAxisLineSymbol ? other.mAxisLineSymbol->clone() : nullptr );
879908
mShowAxis = other.mShowAxis;
909+
mPaintEffect.reset( other.mPaintEffect ? other.mPaintEffect->clone() : nullptr );
880910
return *this;
881911
}
882912

‎src/core/qgsdiagramrenderer.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class QgsReadWriteContext;
4444
class QgsVectorLayer;
4545
class QgsLayerTreeModelLegendNode;
4646
class QgsLayerTreeLayer;
47+
class QgsPaintEffect;
4748

4849
namespace pal { class Layer; } SIP_SKIP
4950

@@ -407,6 +408,7 @@ class CORE_EXPORT QgsDiagramSettings
407408

408409
//! Constructor for QgsDiagramSettings
409410
QgsDiagramSettings();
411+
~QgsDiagramSettings();
410412

411413
//! Copy constructor
412414
QgsDiagramSettings( const QgsDiagramSettings &other );
@@ -618,6 +620,26 @@ class CORE_EXPORT QgsDiagramSettings
618620
*/
619621
void setShowAxis( bool showAxis );
620622

623+
/**
624+
* Returns the paint effect to use while rendering diagrams.
625+
*
626+
* \see setPaintEffect()
627+
*
628+
* \since QGIS 3.12
629+
*/
630+
QgsPaintEffect *paintEffect() const;
631+
632+
/**
633+
* Sets the paint \a effect to use while rendering diagrams.
634+
*
635+
* Ownership of \a effect is transferred to the settings.
636+
*
637+
* \see paintEffect()
638+
*
639+
* \since QGIS 3.12
640+
*/
641+
void setPaintEffect( QgsPaintEffect *effect SIP_TRANSFER );
642+
621643
private:
622644

623645
double mSpacing = 0;
@@ -627,6 +649,7 @@ class CORE_EXPORT QgsDiagramSettings
627649

628650
bool mShowAxis = false;
629651
std::unique_ptr< QgsLineSymbol > mAxisLineSymbol;
652+
std::unique_ptr< QgsPaintEffect > mPaintEffect;
630653

631654
};
632655

‎src/ui/qgsdiagrampropertiesbase.ui

Lines changed: 133 additions & 117 deletions
Large diffs are not rendered by default.

‎tests/src/core/testqgsdiagram.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "qgsmultirenderchecker.h"
4141
#include "qgspallabeling.h"
4242
#include "qgsproject.h"
43+
#include "qgsshadoweffect.h"
4344

4445
/**
4546
* \ingroup UnitTests
@@ -172,6 +173,44 @@ class TestQgsDiagram : public QObject
172173
QVERIFY( imageCheck( "piediagram" ) );
173174
}
174175

176+
void testPaintEffect()
177+
{
178+
QgsDiagramSettings ds;
179+
QColor col1 = Qt::red;
180+
QColor col2 = Qt::yellow;
181+
col1.setAlphaF( 0.5 );
182+
col2.setAlphaF( 0.5 );
183+
ds.categoryColors = QList<QColor>() << col1 << col2;
184+
ds.categoryAttributes = QList<QString>() << QStringLiteral( "\"Pilots\"" ) << QStringLiteral( "\"Cabin Crew\"" );
185+
ds.minimumScale = -1;
186+
ds.maximumScale = -1;
187+
ds.minimumSize = 0;
188+
ds.penColor = Qt::green;
189+
ds.penWidth = .5;
190+
ds.scaleByArea = true;
191+
ds.sizeType = QgsUnitTypes::RenderMillimeters;
192+
ds.size = QSizeF( 5, 5 );
193+
ds.rotationOffset = 0;
194+
ds.setPaintEffect( new QgsDropShadowEffect() );
195+
196+
QgsLinearlyInterpolatedDiagramRenderer *dr = new QgsLinearlyInterpolatedDiagramRenderer();
197+
dr->setLowerValue( 0.0 );
198+
dr->setLowerSize( QSizeF( 0.0, 0.0 ) );
199+
dr->setUpperValue( 10 );
200+
dr->setUpperSize( QSizeF( 40, 40 ) );
201+
dr->setClassificationField( QStringLiteral( "Staff" ) );
202+
dr->setDiagram( new QgsPieDiagram() );
203+
dr->setDiagramSettings( ds );
204+
mPointsLayer->setDiagramRenderer( dr );
205+
206+
QgsDiagramLayerSettings dls = QgsDiagramLayerSettings();
207+
dls.setPlacement( QgsDiagramLayerSettings::OverPoint );
208+
dls.setShowAllDiagrams( true );
209+
mPointsLayer->setDiagramLayerSettings( dls );
210+
211+
QVERIFY( imageCheck( "diagram_effects" ) );
212+
}
213+
175214
void testHistogram()
176215
{
177216
QgsDiagramSettings ds;

0 commit comments

Comments
 (0)
Please sign in to comment.