Skip to content

Commit

Permalink
[FEATURE] Paint effect support for label buffers
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nyalldawson committed Apr 28, 2017
1 parent f0fb1f1 commit b9f102c
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 99 deletions.
14 changes: 13 additions & 1 deletion python/core/qgstextrenderer.sip
Expand Up @@ -130,7 +130,19 @@ class QgsTextBufferSettings
*/
void setBlendMode( QPainter::CompositionMode mode );

/** Reads settings from a layer's custom properties.
/** Returns the current paint effect for the buffer.
* @returns paint effect
* @see setPaintEffect()
*/
QgsPaintEffect* paintEffect() const;

/** Sets the current paint effect for the buffer.
* @param effect paint effect. Ownership is transferred to the buffer settings.
* @see paintEffect()
*/
void setPaintEffect( QgsPaintEffect* effect /Transfer/ );

/** Reads settings from a layer's custom properties.
* @param layer source vector layer
* @see writeToLayer()
*/
Expand Down
69 changes: 65 additions & 4 deletions src/core/qgstextrenderer.cpp
Expand Up @@ -15,12 +15,14 @@
***************************************************************************/

#include "qgstextrenderer.h"
#include "qgis.h"
#include "qgstextrenderer_p.h"
#include "qgsfontutils.h"
#include "qgsvectorlayer.h"
#include "qgssymbollayerutils.h"
#include "qgspainting.h"
#include "qgsmarkersymbollayer.h"
#include "qgspainteffectregistry.h"
#include <QFontDatabase>

Q_GUI_EXPORT extern int qt_defaultDpiX();
Expand Down Expand Up @@ -179,6 +181,17 @@ void QgsTextBufferSettings::setBlendMode( QPainter::CompositionMode mode )
d->blendMode = mode;
}

QgsPaintEffect *QgsTextBufferSettings::paintEffect() const
{
return d->paintEffect;
}

void QgsTextBufferSettings::setPaintEffect( QgsPaintEffect *effect )
{
delete d->paintEffect;
d->paintEffect = effect;
}

void QgsTextBufferSettings::readFromLayer( QgsVectorLayer *layer )
{
// text buffer
Expand Down Expand Up @@ -236,6 +249,16 @@ void QgsTextBufferSettings::readFromLayer( QgsVectorLayer *layer )
d->joinStyle = static_cast< Qt::PenJoinStyle >( layer->customProperty( QStringLiteral( "labeling/bufferJoinStyle" ), QVariant( Qt::RoundJoin ) ).toUInt() );

d->fillBufferInterior = !layer->customProperty( QStringLiteral( "labeling/bufferNoFill" ), QVariant( false ) ).toBool();

if ( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).isValid() )
{
QDomDocument doc( QStringLiteral( "effect" ) );
doc.setContent( layer->customProperty( QStringLiteral( "labeling/bufferEffect" ) ).toString() );
QDomElement effectElem = doc.firstChildElement( QStringLiteral( "effect" ) ).firstChildElement( QStringLiteral( "effect" ) );
setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
}
else
setPaintEffect( nullptr );
}

void QgsTextBufferSettings::writeToLayer( QgsVectorLayer *layer ) const
Expand All @@ -249,6 +272,21 @@ void QgsTextBufferSettings::writeToLayer( QgsVectorLayer *layer ) const
layer->setCustomProperty( QStringLiteral( "labeling/bufferOpacity" ), d->opacity );
layer->setCustomProperty( QStringLiteral( "labeling/bufferJoinStyle" ), static_cast< unsigned int >( d->joinStyle ) );
layer->setCustomProperty( QStringLiteral( "labeling/bufferBlendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) );

if ( d->paintEffect && !QgsPaintEffectRegistry::isDefaultStack( d->paintEffect ) )
{
QDomDocument doc( QStringLiteral( "effect" ) );
QDomElement effectElem = doc.createElement( QStringLiteral( "effect" ) );
d->paintEffect->saveProperties( doc, effectElem );
QString effectProps;
QTextStream stream( &effectProps );
effectElem.save( stream, -1 );
layer->setCustomProperty( QStringLiteral( "labeling/bufferEffect" ), effectProps );
}
else
{
layer->removeCustomProperty( QStringLiteral( "labeling/bufferEffect" ) );
}
}

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

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

Expand Down Expand Up @@ -1809,9 +1854,25 @@ void QgsTextRenderer::drawBuffer( QgsRenderContext &context, const QgsTextRender
QPicture buffPict;
QPainter buffp;
buffp.begin( &buffPict );
buffp.setPen( pen );
buffp.setBrush( tmpColor );
buffp.drawPath( path );

if ( buffer.paintEffect() && buffer.paintEffect()->enabled() )
{
context.setPainter( &buffp );

buffer.paintEffect()->begin( context );
context.painter()->setPen( pen );
context.painter()->setBrush( tmpColor );
context.painter()->drawPath( path );
buffer.paintEffect()->end( context );

context.setPainter( p );
}
else
{
buffp.setPen( pen );
buffp.setBrush( tmpColor );
buffp.drawPath( path );
}
buffp.end();

if ( format.shadow().enabled() && format.shadow().shadowPlacement() == QgsTextShadowSettings::ShadowBuffer )
Expand All @@ -1822,7 +1883,6 @@ void QgsTextRenderer::drawBuffer( QgsRenderContext &context, const QgsTextRender
bufferComponent.pictureBuffer = penSize / 2.0;
drawShadow( context, bufferComponent, format );
}

p->save();
if ( context.useAdvancedEffects() )
{
Expand Down Expand Up @@ -2562,3 +2622,4 @@ void QgsTextRenderer::drawTextInternal( TextPart drawType,
i++;
}
}

12 changes: 12 additions & 0 deletions src/core/qgstextrenderer.h
Expand Up @@ -31,6 +31,7 @@ class QgsTextBackgroundSettingsPrivate;
class QgsTextShadowSettingsPrivate;
class QgsTextSettingsPrivate;
class QgsVectorLayer;
class QgsPaintEffect;

/** \class QgsTextBufferSettings
* \ingroup core
Expand Down Expand Up @@ -191,6 +192,17 @@ class CORE_EXPORT QgsTextBufferSettings
*/
QDomElement writeXml( QDomDocument &doc ) const;

/** Returns the current paint effect for the buffer.
* \returns paint effect
* \see setPaintEffect()
*/
QgsPaintEffect *paintEffect() const;

/** Sets the current paint \a effect for the buffer.
* \param effect paint effect. Ownership is transferred to the buffer settings.
* \see paintEffect()
*/
void setPaintEffect( QgsPaintEffect *effect );

private:

Expand Down
9 changes: 9 additions & 0 deletions src/core/qgstextrenderer_p.h
Expand Up @@ -22,6 +22,7 @@
#include "qgsmapunitscale.h"
#include "qgsunittypes.h"
#include "qgsapplication.h"
#include "qgspainteffect.h"
#include <QSharedData>
#include <QPainter>

Expand Down Expand Up @@ -50,6 +51,7 @@ class CORE_EXPORT QgsTextBufferSettingsPrivate : public QSharedData
, fillBufferInterior( false )
, joinStyle( Qt::RoundJoin )
, blendMode( QPainter::CompositionMode_SourceOver )
, paintEffect( nullptr )
{
}

Expand All @@ -64,9 +66,15 @@ class CORE_EXPORT QgsTextBufferSettingsPrivate : public QSharedData
, fillBufferInterior( other.fillBufferInterior )
, joinStyle( other.joinStyle )
, blendMode( other.blendMode )
, paintEffect( other.paintEffect ? other.paintEffect->clone() : nullptr )
{
}

~QgsTextBufferSettingsPrivate()
{
delete paintEffect;
}

bool enabled;
double size;
QgsUnitTypes::RenderUnit sizeUnit;
Expand All @@ -76,6 +84,7 @@ class CORE_EXPORT QgsTextBufferSettingsPrivate : public QSharedData
bool fillBufferInterior;
Qt::PenJoinStyle joinStyle;
QPainter::CompositionMode blendMode;
QgsPaintEffect *paintEffect;
};


Expand Down
11 changes: 10 additions & 1 deletion src/gui/effects/qgseffectstackpropertieswidget.cpp
Expand Up @@ -467,7 +467,16 @@ void QgsEffectStackCompactWidget::showDialog()
}
connect( widget, &QgsPanelWidget::widgetChanged, this, &QgsEffectStackCompactWidget::updateEffectLive );
connect( widget, &QgsPanelWidget::panelAccepted, this, &QgsEffectStackCompactWidget::updateAcceptWidget );
openPanel( widget );

QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( qobject_cast< QWidget * >( parent() ) );
if ( panel && panel->dockMode() )
{
panel->openPanel( widget );
}
else
{
openPanel( widget );
}
}

void QgsEffectStackCompactWidget::enableToggled( bool checked )
Expand Down
19 changes: 18 additions & 1 deletion src/gui/qgstextformatwidget.cpp
Expand Up @@ -24,6 +24,8 @@
#include "qgssubstitutionlistwidget.h"
#include "qgspallabeling.h" // for enum values
#include "qgssettings.h"
#include "qgseffectstack.h"
#include "qgspainteffectregistry.h"

QgsTextFormatWidget::QgsTextFormatWidget( const QgsTextFormat &format, QgsMapCanvas *mapCanvas, QWidget *parent )
: QWidget( parent )
Expand Down Expand Up @@ -259,6 +261,10 @@ void QgsTextFormatWidget::initWidget()

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

mBufferEffect.reset( QgsPaintEffectRegistry::defaultStack() );
connect( mBufferEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );

setDockMode( false );


Expand Down Expand Up @@ -611,7 +617,14 @@ void QgsTextFormatWidget::updateWidgetForFormat( const QgsTextFormat &format )
mBufferJoinStyleComboBox->setPenJoinStyle( buffer.joinStyle() );
mBufferTranspFillChbx->setChecked( buffer.fillBufferInterior() );
comboBufferBlendMode->setBlendMode( buffer.blendMode() );

if ( buffer.paintEffect() )
mBufferEffect.reset( buffer.paintEffect()->clone() );
else
{
mBufferEffect.reset( QgsPaintEffectRegistry::defaultStack() );
mBufferEffect->setEnabled( false );
}
mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );

mFontSizeUnitWidget->setUnit( format.sizeUnit() );
mFontSizeUnitWidget->setMapUnitScale( format.sizeMapUnitScale() );
Expand Down Expand Up @@ -735,6 +748,10 @@ QgsTextFormat QgsTextFormatWidget::format() const
buffer.setJoinStyle( mBufferJoinStyleComboBox->penJoinStyle() );
buffer.setFillBufferInterior( mBufferTranspFillChbx->isChecked() );
buffer.setBlendMode( comboBufferBlendMode->blendMode() );
if ( mBufferEffect && !QgsPaintEffectRegistry::isDefaultStack( mBufferEffect.get() ) )
buffer.setPaintEffect( mBufferEffect->clone() );
else
buffer.setPaintEffect( nullptr );
format.setBuffer( buffer );

// shape background
Expand Down
1 change: 1 addition & 0 deletions src/gui/qgstextformatwidget.h
Expand Up @@ -136,6 +136,7 @@ class GUI_EXPORT QgsTextFormatWidget : public QWidget, protected Ui::QgsTextForm
Mode mWidgetMode;
QgsMapCanvas *mMapCanvas = nullptr;
QgsCharacterSelectorDialog *mCharDlg = nullptr;
std::unique_ptr< QgsPaintEffect > mBufferEffect;

QFontDatabase mFontDB;

Expand Down

0 comments on commit b9f102c

Please sign in to comment.