Skip to content

Commit b9f102c

Browse files
committedApr 28, 2017
[FEATURE] Paint effect support for label buffers
Allows applying a paint effect (such as blurs) to label buffers. Blurring label buffers is a great way to get the text readability of a label buffer without the distracting halo effect.
1 parent f0fb1f1 commit b9f102c

File tree

9 files changed

+242
-99
lines changed

9 files changed

+242
-99
lines changed
 

‎python/core/qgstextrenderer.sip

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,19 @@ class QgsTextBufferSettings
130130
*/
131131
void setBlendMode( QPainter::CompositionMode mode );
132132

133-
/** Reads settings from a layer's custom properties.
133+
/** Returns the current paint effect for the buffer.
134+
* @returns paint effect
135+
* @see setPaintEffect()
136+
*/
137+
QgsPaintEffect* paintEffect() const;
138+
139+
/** Sets the current paint effect for the buffer.
140+
* @param effect paint effect. Ownership is transferred to the buffer settings.
141+
* @see paintEffect()
142+
*/
143+
void setPaintEffect( QgsPaintEffect* effect /Transfer/ );
144+
145+
/** Reads settings from a layer's custom properties.
134146
* @param layer source vector layer
135147
* @see writeToLayer()
136148
*/

‎src/core/qgstextrenderer.cpp

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
***************************************************************************/
1616

1717
#include "qgstextrenderer.h"
18+
#include "qgis.h"
1819
#include "qgstextrenderer_p.h"
1920
#include "qgsfontutils.h"
2021
#include "qgsvectorlayer.h"
2122
#include "qgssymbollayerutils.h"
2223
#include "qgspainting.h"
2324
#include "qgsmarkersymbollayer.h"
25+
#include "qgspainteffectregistry.h"
2426
#include <QFontDatabase>
2527

2628
Q_GUI_EXPORT extern int qt_defaultDpiX();
@@ -179,6 +181,17 @@ void QgsTextBufferSettings::setBlendMode( QPainter::CompositionMode mode )
179181
d->blendMode = mode;
180182
}
181183

184+
QgsPaintEffect *QgsTextBufferSettings::paintEffect() const
185+
{
186+
return d->paintEffect;
187+
}
188+
189+
void QgsTextBufferSettings::setPaintEffect( QgsPaintEffect *effect )
190+
{
191+
delete d->paintEffect;
192+
d->paintEffect = effect;
193+
}
194+
182195
void QgsTextBufferSettings::readFromLayer( QgsVectorLayer *layer )
183196
{
184197
// text buffer
@@ -236,6 +249,16 @@ void QgsTextBufferSettings::readFromLayer( QgsVectorLayer *layer )
236249
d->joinStyle = static_cast< Qt::PenJoinStyle >( layer->customProperty( QStringLiteral( "labeling/bufferJoinStyle" ), QVariant( Qt::RoundJoin ) ).toUInt() );
237250

238251
d->fillBufferInterior = !layer->customProperty( QStringLiteral( "labeling/bufferNoFill" ), QVariant( false ) ).toBool();
252+
253+
if ( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).isValid() )
254+
{
255+
QDomDocument doc( QStringLiteral( "effect" ) );
256+
doc.setContent( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).toString() );
257+
QDomElement effectElem = doc.firstChildElement( QStringLiteral( "effect" ) ).firstChildElement( QStringLiteral( "effect" ) );
258+
setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
259+
}
260+
else
261+
setPaintEffect( nullptr );
239262
}
240263

241264
void QgsTextBufferSettings::writeToLayer( QgsVectorLayer *layer ) const
@@ -249,6 +272,21 @@ void QgsTextBufferSettings::writeToLayer( QgsVectorLayer *layer ) const
249272
layer->setCustomProperty( QStringLiteral( "labeling/bufferOpacity" ), d->opacity );
250273
layer->setCustomProperty( QStringLiteral( "labeling/bufferJoinStyle" ), static_cast< unsigned int >( d->joinStyle ) );
251274
layer->setCustomProperty( QStringLiteral( "labeling/bufferBlendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) );
275+
276+
if ( d->paintEffect && !QgsPaintEffectRegistry::isDefaultStack( d->paintEffect ) )
277+
{
278+
QDomDocument doc( QStringLiteral( "effect" ) );
279+
QDomElement effectElem = doc.createElement( QStringLiteral( "effect" ) );
280+
d->paintEffect->saveProperties( doc, effectElem );
281+
QString effectProps;
282+
QTextStream stream( &effectProps );
283+
effectElem.save( stream, -1 );
284+
layer->setCustomProperty( QStringLiteral( "labeling/bufferEffect" ), effectProps );
285+
}
286+
else
287+
{
288+
layer->removeCustomProperty( QStringLiteral( "labeling/bufferEffect" ) );
289+
}
252290
}
253291

254292
void QgsTextBufferSettings::readXml( const QDomElement &elem )
@@ -309,6 +347,11 @@ void QgsTextBufferSettings::readXml( const QDomElement &elem )
309347
static_cast< QgsPainting::BlendMode >( textBufferElem.attribute( QStringLiteral( "bufferBlendMode" ), QString::number( QgsPainting::BlendNormal ) ).toUInt() ) );
310348
d->joinStyle = static_cast< Qt::PenJoinStyle >( textBufferElem.attribute( QStringLiteral( "bufferJoinStyle" ), QString::number( Qt::RoundJoin ) ).toUInt() );
311349
d->fillBufferInterior = !textBufferElem.attribute( QStringLiteral( "bufferNoFill" ), QStringLiteral( "0" ) ).toInt();
350+
QDomElement effectElem = textBufferElem.firstChildElement( QStringLiteral( "effect" ) );
351+
if ( !effectElem.isNull() )
352+
setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
353+
else
354+
setPaintEffect( nullptr );
312355
}
313356

314357
QDomElement QgsTextBufferSettings::writeXml( QDomDocument &doc ) const
@@ -324,6 +367,8 @@ QDomElement QgsTextBufferSettings::writeXml( QDomDocument &doc ) const
324367
textBufferElem.setAttribute( QStringLiteral( "bufferOpacity" ), d->opacity );
325368
textBufferElem.setAttribute( QStringLiteral( "bufferJoinStyle" ), static_cast< unsigned int >( d->joinStyle ) );
326369
textBufferElem.setAttribute( QStringLiteral( "bufferBlendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) );
370+
if ( d->paintEffect && !QgsPaintEffectRegistry::isDefaultStack( d->paintEffect ) )
371+
d->paintEffect->saveProperties( doc, textBufferElem );
327372
return textBufferElem;
328373
}
329374

@@ -1809,9 +1854,25 @@ void QgsTextRenderer::drawBuffer( QgsRenderContext &context, const QgsTextRender
18091854
QPicture buffPict;
18101855
QPainter buffp;
18111856
buffp.begin( &buffPict );
1812-
buffp.setPen( pen );
1813-
buffp.setBrush( tmpColor );
1814-
buffp.drawPath( path );
1857+
1858+
if ( buffer.paintEffect() && buffer.paintEffect()->enabled() )
1859+
{
1860+
context.setPainter( &buffp );
1861+
1862+
buffer.paintEffect()->begin( context );
1863+
context.painter()->setPen( pen );
1864+
context.painter()->setBrush( tmpColor );
1865+
context.painter()->drawPath( path );
1866+
buffer.paintEffect()->end( context );
1867+
1868+
context.setPainter( p );
1869+
}
1870+
else
1871+
{
1872+
buffp.setPen( pen );
1873+
buffp.setBrush( tmpColor );
1874+
buffp.drawPath( path );
1875+
}
18151876
buffp.end();
18161877

18171878
if ( format.shadow().enabled() && format.shadow().shadowPlacement() == QgsTextShadowSettings::ShadowBuffer )
@@ -1822,7 +1883,6 @@ void QgsTextRenderer::drawBuffer( QgsRenderContext &context, const QgsTextRender
18221883
bufferComponent.pictureBuffer = penSize / 2.0;
18231884
drawShadow( context, bufferComponent, format );
18241885
}
1825-
18261886
p->save();
18271887
if ( context.useAdvancedEffects() )
18281888
{
@@ -2562,3 +2622,4 @@ void QgsTextRenderer::drawTextInternal( TextPart drawType,
25622622
i++;
25632623
}
25642624
}
2625+

‎src/core/qgstextrenderer.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class QgsTextBackgroundSettingsPrivate;
3131
class QgsTextShadowSettingsPrivate;
3232
class QgsTextSettingsPrivate;
3333
class QgsVectorLayer;
34+
class QgsPaintEffect;
3435

3536
/** \class QgsTextBufferSettings
3637
* \ingroup core
@@ -191,6 +192,17 @@ class CORE_EXPORT QgsTextBufferSettings
191192
*/
192193
QDomElement writeXml( QDomDocument &doc ) const;
193194

195+
/** Returns the current paint effect for the buffer.
196+
* \returns paint effect
197+
* \see setPaintEffect()
198+
*/
199+
QgsPaintEffect *paintEffect() const;
200+
201+
/** Sets the current paint \a effect for the buffer.
202+
* \param effect paint effect. Ownership is transferred to the buffer settings.
203+
* \see paintEffect()
204+
*/
205+
void setPaintEffect( QgsPaintEffect *effect );
194206

195207
private:
196208

‎src/core/qgstextrenderer_p.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "qgsmapunitscale.h"
2323
#include "qgsunittypes.h"
2424
#include "qgsapplication.h"
25+
#include "qgspainteffect.h"
2526
#include <QSharedData>
2627
#include <QPainter>
2728

@@ -50,6 +51,7 @@ class CORE_EXPORT QgsTextBufferSettingsPrivate : public QSharedData
5051
, fillBufferInterior( false )
5152
, joinStyle( Qt::RoundJoin )
5253
, blendMode( QPainter::CompositionMode_SourceOver )
54+
, paintEffect( nullptr )
5355
{
5456
}
5557

@@ -64,9 +66,15 @@ class CORE_EXPORT QgsTextBufferSettingsPrivate : public QSharedData
6466
, fillBufferInterior( other.fillBufferInterior )
6567
, joinStyle( other.joinStyle )
6668
, blendMode( other.blendMode )
69+
, paintEffect( other.paintEffect ? other.paintEffect->clone() : nullptr )
6770
{
6871
}
6972

73+
~QgsTextBufferSettingsPrivate()
74+
{
75+
delete paintEffect;
76+
}
77+
7078
bool enabled;
7179
double size;
7280
QgsUnitTypes::RenderUnit sizeUnit;
@@ -76,6 +84,7 @@ class CORE_EXPORT QgsTextBufferSettingsPrivate : public QSharedData
7684
bool fillBufferInterior;
7785
Qt::PenJoinStyle joinStyle;
7886
QPainter::CompositionMode blendMode;
87+
QgsPaintEffect *paintEffect;
7988
};
8089

8190

‎src/gui/effects/qgseffectstackpropertieswidget.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,16 @@ void QgsEffectStackCompactWidget::showDialog()
467467
}
468468
connect( widget, &QgsPanelWidget::widgetChanged, this, &QgsEffectStackCompactWidget::updateEffectLive );
469469
connect( widget, &QgsPanelWidget::panelAccepted, this, &QgsEffectStackCompactWidget::updateAcceptWidget );
470-
openPanel( widget );
470+
471+
QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( qobject_cast< QWidget * >( parent() ) );
472+
if ( panel && panel->dockMode() )
473+
{
474+
panel->openPanel( widget );
475+
}
476+
else
477+
{
478+
openPanel( widget );
479+
}
471480
}
472481

473482
void QgsEffectStackCompactWidget::enableToggled( bool checked )

‎src/gui/qgstextformatwidget.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include "qgssubstitutionlistwidget.h"
2525
#include "qgspallabeling.h" // for enum values
2626
#include "qgssettings.h"
27+
#include "qgseffectstack.h"
28+
#include "qgspainteffectregistry.h"
2729

2830
QgsTextFormatWidget::QgsTextFormatWidget( const QgsTextFormat &format, QgsMapCanvas *mapCanvas, QWidget *parent )
2931
: QWidget( parent )
@@ -259,6 +261,10 @@ void QgsTextFormatWidget::initWidget()
259261

260262
mLabelingOptionsListWidget->setCurrentRow( settings.value( QStringLiteral( "Windows/Labeling/Tab" ), 0 ).toInt() );
261263

264+
mBufferEffect.reset( QgsPaintEffectRegistry::defaultStack() );
265+
connect( mBufferEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
266+
mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );
267+
262268
setDockMode( false );
263269

264270

@@ -611,7 +617,14 @@ void QgsTextFormatWidget::updateWidgetForFormat( const QgsTextFormat &format )
611617
mBufferJoinStyleComboBox->setPenJoinStyle( buffer.joinStyle() );
612618
mBufferTranspFillChbx->setChecked( buffer.fillBufferInterior() );
613619
comboBufferBlendMode->setBlendMode( buffer.blendMode() );
614-
620+
if ( buffer.paintEffect() )
621+
mBufferEffect.reset( buffer.paintEffect()->clone() );
622+
else
623+
{
624+
mBufferEffect.reset( QgsPaintEffectRegistry::defaultStack() );
625+
mBufferEffect->setEnabled( false );
626+
}
627+
mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );
615628

616629
mFontSizeUnitWidget->setUnit( format.sizeUnit() );
617630
mFontSizeUnitWidget->setMapUnitScale( format.sizeMapUnitScale() );
@@ -735,6 +748,10 @@ QgsTextFormat QgsTextFormatWidget::format() const
735748
buffer.setJoinStyle( mBufferJoinStyleComboBox->penJoinStyle() );
736749
buffer.setFillBufferInterior( mBufferTranspFillChbx->isChecked() );
737750
buffer.setBlendMode( comboBufferBlendMode->blendMode() );
751+
if ( mBufferEffect && !QgsPaintEffectRegistry::isDefaultStack( mBufferEffect.get() ) )
752+
buffer.setPaintEffect( mBufferEffect->clone() );
753+
else
754+
buffer.setPaintEffect( nullptr );
738755
format.setBuffer( buffer );
739756

740757
// shape background

‎src/gui/qgstextformatwidget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class GUI_EXPORT QgsTextFormatWidget : public QWidget, protected Ui::QgsTextForm
136136
Mode mWidgetMode;
137137
QgsMapCanvas *mMapCanvas = nullptr;
138138
QgsCharacterSelectorDialog *mCharDlg = nullptr;
139+
std::unique_ptr< QgsPaintEffect > mBufferEffect;
139140

140141
QFontDatabase mFontDB;
141142

0 commit comments

Comments
 (0)