Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #43043 from nirvn/labeling_shields_imp
[feature][labeling] Use fill symbols to render rectangle,square,circle,ellipse background shields
  • Loading branch information
nirvn committed May 4, 2021
2 parents 46287b8 + 65ba359 commit c27e22f
Show file tree
Hide file tree
Showing 28 changed files with 361 additions and 102 deletions.
Expand Up @@ -141,6 +141,38 @@ to the background settings.
.. seealso:: :py:func:`markerSymbol`

.. versionadded:: 3.10
%End

QgsFillSymbol *fillSymbol() const;
%Docstring
Returns the fill symbol to be rendered in the background. Ownership remains with
the background settings.

.. note::

This is only used when the :py:func:`~QgsTextBackgroundSettings.type` is QgsTextBackgroundSettings.ShapeRectangle,
QgsTextBackgroundSettings.ShapeSquare, QgsTextBackgroundSettings.ShapeCircle or
QgsTextBackgroundSettings.ShapeEllipse

.. seealso:: :py:func:`setFillSymbol`

.. versionadded:: 3.20
%End

void setFillSymbol( QgsFillSymbol *symbol /Transfer/ );
%Docstring
Sets the current fill ``symbol`` for the background shape. Ownership is transferred
to the background settings.

.. note::

This is only used when the :py:func:`~QgsTextBackgroundSettings.type` is QgsTextBackgroundSettings.ShapeRectangle,
QgsTextBackgroundSettings.ShapeSquare, QgsTextBackgroundSettings.ShapeCircle or
QgsTextBackgroundSettings.ShapeEllipse

.. seealso:: :py:func:`fillSymbol`

.. versionadded:: 3.20
%End

SizeType sizeType() const;
Expand Down Expand Up @@ -447,6 +479,11 @@ Returns the color used for filing the background shape.
.. seealso:: :py:func:`setFillColor`

.. seealso:: :py:func:`strokeColor`

.. note::

As of QGIS 3.20, using this function is only recommended for SVG backgrounds, while
other background types should be configured through their symbols.
%End

void setFillColor( const QColor &color );
Expand All @@ -458,6 +495,11 @@ Sets the color used for filing the background shape.
.. seealso:: :py:func:`fillColor`

.. seealso:: :py:func:`setStrokeColor`

.. note::

As of QGIS 3.20, using this function is only recommended for SVG backgrounds, while
other background types should be configured through their symbols.
%End

QColor strokeColor() const;
Expand All @@ -467,6 +509,11 @@ Returns the color used for outlining the background shape.
.. seealso:: :py:func:`setStrokeColor`

.. seealso:: :py:func:`fillColor`

.. note::

As of QGIS 3.20, using this function is only recommended for SVG backgrounds, while
other background types should be configured through their symbols.
%End

void setStrokeColor( const QColor &color );
Expand Down Expand Up @@ -498,6 +545,11 @@ Sets the width of the shape's stroke (stroke). Units are specified through
.. seealso:: :py:func:`strokeWidth`

.. seealso:: :py:func:`setStrokeWidthUnit`

.. note::

As of QGIS 3.20, using this function is only recommended for SVG backgrounds, while
other background types should be configured through their symbols.
%End

QgsUnitTypes::RenderUnit strokeWidthUnit() const;
Expand All @@ -518,6 +570,11 @@ Sets the units used for the shape's stroke width.
.. seealso:: :py:func:`strokeWidthUnit`

.. seealso:: :py:func:`setStrokeWidth`

.. note::

As of QGIS 3.20, using this function is only recommended for SVG backgrounds, while
other background types should be configured through their symbols.
%End

QgsMapUnitScale strokeWidthMapUnitScale() const;
Expand All @@ -540,6 +597,11 @@ Sets the map unit scale object for the shape stroke width. This is only used if
.. seealso:: :py:func:`strokeWidthMapUnitScale`

.. seealso:: :py:func:`setStrokeWidthUnit`

.. note::

As of QGIS 3.20, using this function is only recommended for SVG backgrounds, while
other background types should be configured through their symbols.
%End

Qt::PenJoinStyle joinStyle() const;
Expand All @@ -556,6 +618,11 @@ Sets the join style used for drawing the background shape.
:param style: join style

.. seealso:: :py:func:`joinStyle`

.. note::

As of QGIS 3.20, using this function is only recommended for SVG backgrounds, while
other background types should be configured through their symbols.
%End

const QgsPaintEffect *paintEffect() const;
Expand Down Expand Up @@ -601,9 +668,16 @@ Write settings into a DOM element.
%Docstring
Updates the format by evaluating current values of data defined properties.

.. note::

Since QGIS 3.20, data defined fill color, stroke color, stroke width, and
pen join style will only modify SVG backgrounds. For other background types, the
data defined properties within symbols are to be used.

.. versionadded:: 3.10
%End


QSet<QString> referencedFields( const QgsRenderContext &context ) const;
%Docstring
Returns all field names referenced by the configuration (e.g. from data defined properties).
Expand Down
138 changes: 133 additions & 5 deletions src/core/textrenderer/qgstextbackgroundsettings.cpp
Expand Up @@ -18,13 +18,26 @@
#include "qgsvectorlayer.h"
#include "qgspallabeling.h"
#include "qgssymbollayerutils.h"
#include "qgsfillsymbollayer.h"
#include "qgspainting.h"
#include "qgstextrendererutils.h"
#include "qgspainteffectregistry.h"

QgsTextBackgroundSettings::QgsTextBackgroundSettings()
{
d = new QgsTextBackgroundSettingsPrivate();

// Create a default fill symbol to preserve API promise until QGIS 4.0
QgsSimpleFillSymbolLayer *fill = new QgsSimpleFillSymbolLayer( d->fillColor, Qt::SolidPattern, d->strokeColor );
fill->setStrokeWidth( d->strokeWidth );
fill->setStrokeWidthUnit( d->strokeWidthUnits );
fill->setStrokeWidthMapUnitScale( d->strokeWidthMapUnitScale );
fill->setStrokeStyle( !qgsDoubleNear( d->strokeWidth, 0.0 ) ? Qt::SolidLine : Qt::NoPen );
fill->setPenJoinStyle( d->joinStyle );

QgsFillSymbol *fillSymbol = new QgsFillSymbol();
fillSymbol->changeSymbolLayer( 0, fill );
setFillSymbol( fillSymbol );
}

QgsTextBackgroundSettings::QgsTextBackgroundSettings( const QgsTextBackgroundSettings &other ) //NOLINT
Expand Down Expand Up @@ -79,6 +92,10 @@ bool QgsTextBackgroundSettings::operator==( const QgsTextBackgroundSettings &oth
|| ( d->markerSymbol && QgsSymbolLayerUtils::symbolProperties( d->markerSymbol.get() ) != QgsSymbolLayerUtils::symbolProperties( other.markerSymbol() ) ) )
return false;

if ( static_cast< bool >( d->fillSymbol ) != static_cast< bool >( other.fillSymbol() )
|| ( d->fillSymbol && QgsSymbolLayerUtils::symbolProperties( d->fillSymbol.get() ) != QgsSymbolLayerUtils::symbolProperties( other.fillSymbol() ) ) )
return false;

return true;
}

Expand Down Expand Up @@ -127,6 +144,16 @@ void QgsTextBackgroundSettings::setMarkerSymbol( QgsMarkerSymbol *symbol )
d->markerSymbol.reset( symbol );
}

QgsFillSymbol *QgsTextBackgroundSettings::fillSymbol() const
{
return d->fillSymbol.get();
}

void QgsTextBackgroundSettings::setFillSymbol( QgsFillSymbol *symbol )
{
d->fillSymbol.reset( symbol );
}

QgsTextBackgroundSettings::SizeType QgsTextBackgroundSettings::sizeType() const
{
return d->sizeType;
Expand Down Expand Up @@ -275,6 +302,10 @@ QColor QgsTextBackgroundSettings::fillColor() const
void QgsTextBackgroundSettings::setFillColor( const QColor &color )
{
d->fillColor = color;
if ( d->fillSymbol && d->fillSymbol->symbolLayers().at( 0 )->layerType() == QStringLiteral( "SimpleFill" ) )
{
qgis::down_cast< QgsSimpleFillSymbolLayer * >( d->fillSymbol->symbolLayers().at( 0 ) )->setColor( color );
}
}

QColor QgsTextBackgroundSettings::strokeColor() const
Expand All @@ -285,6 +316,10 @@ QColor QgsTextBackgroundSettings::strokeColor() const
void QgsTextBackgroundSettings::setStrokeColor( const QColor &color )
{
d->strokeColor = color;
if ( d->fillSymbol && d->fillSymbol->symbolLayers().at( 0 )->layerType() == QStringLiteral( "SimpleFill" ) )
{
qgis::down_cast< QgsSimpleFillSymbolLayer * >( d->fillSymbol->symbolLayers().at( 0 ) )->setStrokeColor( color );
}
}

double QgsTextBackgroundSettings::strokeWidth() const
Expand All @@ -295,6 +330,12 @@ double QgsTextBackgroundSettings::strokeWidth() const
void QgsTextBackgroundSettings::setStrokeWidth( double width )
{
d->strokeWidth = width;
if ( d->fillSymbol && d->fillSymbol->symbolLayers().at( 0 )->layerType() == QStringLiteral( "SimpleFill" ) )
{
QgsSimpleFillSymbolLayer *fill = qgis::down_cast< QgsSimpleFillSymbolLayer * >( d->fillSymbol->symbolLayers().at( 0 ) );
fill->setStrokeWidth( width );
fill->setStrokeStyle( !qgsDoubleNear( width, 0.0 ) ? Qt::SolidLine : Qt::NoPen );
}
}

QgsUnitTypes::RenderUnit QgsTextBackgroundSettings::strokeWidthUnit() const
Expand All @@ -305,6 +346,10 @@ QgsUnitTypes::RenderUnit QgsTextBackgroundSettings::strokeWidthUnit() const
void QgsTextBackgroundSettings::setStrokeWidthUnit( QgsUnitTypes::RenderUnit units )
{
d->strokeWidthUnits = units;
if ( d->fillSymbol && d->fillSymbol->symbolLayers().at( 0 )->layerType() == QStringLiteral( "SimpleFill" ) )
{
qgis::down_cast< QgsSimpleFillSymbolLayer * >( d->fillSymbol->symbolLayers().at( 0 ) )->setStrokeWidthUnit( units );
}
}

QgsMapUnitScale QgsTextBackgroundSettings::strokeWidthMapUnitScale() const
Expand All @@ -315,6 +360,10 @@ QgsMapUnitScale QgsTextBackgroundSettings::strokeWidthMapUnitScale() const
void QgsTextBackgroundSettings::setStrokeWidthMapUnitScale( const QgsMapUnitScale &scale )
{
d->strokeWidthMapUnitScale = scale;
if ( d->fillSymbol && d->fillSymbol->symbolLayers().at( 0 )->layerType() == QStringLiteral( "SimpleFill" ) )
{
qgis::down_cast< QgsSimpleFillSymbolLayer * >( d->fillSymbol->symbolLayers().at( 0 ) )->setStrokeWidthMapUnitScale( scale );
}
}

Qt::PenJoinStyle QgsTextBackgroundSettings::joinStyle() const
Expand All @@ -325,6 +374,10 @@ Qt::PenJoinStyle QgsTextBackgroundSettings::joinStyle() const
void QgsTextBackgroundSettings::setJoinStyle( Qt::PenJoinStyle style )
{
d->joinStyle = style;
if ( d->fillSymbol && d->fillSymbol->symbolLayers().at( 0 )->layerType() == QStringLiteral( "SimpleFill" ) )
{
qgis::down_cast< QgsSimpleFillSymbolLayer * >( d->fillSymbol->symbolLayers().at( 0 ) )->setPenJoinStyle( style );
}
}

const QgsPaintEffect *QgsTextBackgroundSettings::paintEffect() const
Expand Down Expand Up @@ -589,11 +642,39 @@ void QgsTextBackgroundSettings::readXml( const QDomElement &elem, const QgsReadW
else
setPaintEffect( nullptr );

const QDomElement symbolElem = backgroundElem.firstChildElement( QStringLiteral( "symbol" ) );
if ( !symbolElem.isNull() )
setMarkerSymbol( QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( symbolElem, context ) );
else
setMarkerSymbol( nullptr );
setMarkerSymbol( nullptr );
setFillSymbol( nullptr );
const QDomNodeList symbols = backgroundElem.elementsByTagName( QStringLiteral( "symbol" ) );
for ( int i = 0; i < symbols.size(); ++i )
{
if ( symbols.at( i ).isElement() )
{
const QDomElement symbolElement = symbols.at( i ).toElement();
const QString symbolElementName = symbolElement.attribute( QStringLiteral( "name" ) );
if ( symbolElementName == QStringLiteral( "markerSymbol" ) )
{
setMarkerSymbol( QgsSymbolLayerUtils::loadSymbol< QgsMarkerSymbol >( symbolElement, context ) );
}
else if ( symbolElementName == QStringLiteral( "fillSymbol" ) )
{
setFillSymbol( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( symbolElement, context ) );
}
}
}

if ( !d->fillSymbol )
{
QgsSimpleFillSymbolLayer *fill = new QgsSimpleFillSymbolLayer( d->fillColor, Qt::SolidPattern, d->strokeColor );
fill->setStrokeWidth( d->strokeWidth );
fill->setStrokeWidthUnit( d->strokeWidthUnits );
fill->setStrokeWidthMapUnitScale( d->strokeWidthMapUnitScale );
fill->setStrokeStyle( !qgsDoubleNear( d->strokeWidth, 0.0 ) ? Qt::SolidLine : Qt::NoPen );
fill->setPenJoinStyle( d->joinStyle );

QgsFillSymbol *fillSymbol = new QgsFillSymbol();
fillSymbol->changeSymbolLayer( 0, fill );
setFillSymbol( fillSymbol );
}
}

QDomElement QgsTextBackgroundSettings::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
Expand Down Expand Up @@ -631,9 +712,50 @@ QDomElement QgsTextBackgroundSettings::writeXml( QDomDocument &doc, const QgsRea
if ( d->markerSymbol )
backgroundElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "markerSymbol" ), d->markerSymbol.get(), doc, context ) );

if ( d->fillSymbol )
backgroundElem.appendChild( QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "fillSymbol" ), d->fillSymbol.get(), doc, context ) );

return backgroundElem;
}

void QgsTextBackgroundSettings::upgradeDataDefinedProperties( QgsPropertyCollection &properties )
{
if ( !d->fillSymbol || d->fillSymbol->symbolLayers().at( 0 )->layerType() != QStringLiteral( "SimpleFill" ) )
return;
QgsSimpleFillSymbolLayer *fill = qgis::down_cast< QgsSimpleFillSymbolLayer * >( d->fillSymbol->symbolLayers().at( 0 ) );

if ( d->type != QgsTextBackgroundSettings::ShapeSVG )
{
if ( properties.hasProperty( QgsPalLayerSettings::ShapeFillColor ) &&
!fill->dataDefinedProperties().hasProperty( QgsSymbolLayer::PropertyFillColor ) )
{
fill->dataDefinedProperties().setProperty( QgsSymbolLayer::PropertyFillColor, properties.property( QgsPalLayerSettings::ShapeFillColor ) );
properties.setProperty( QgsPalLayerSettings::ShapeFillColor, QgsProperty() );
}

if ( properties.hasProperty( QgsPalLayerSettings::ShapeStrokeColor ) &&
!fill->dataDefinedProperties().hasProperty( QgsSymbolLayer::PropertyStrokeColor ) )
{
fill->dataDefinedProperties().setProperty( QgsSymbolLayer::PropertyStrokeColor, properties.property( QgsPalLayerSettings::ShapeStrokeColor ) );
properties.setProperty( QgsPalLayerSettings::ShapeStrokeColor, QgsProperty() );
}

if ( properties.hasProperty( QgsPalLayerSettings::ShapeStrokeWidth ) &&
!fill->dataDefinedProperties().hasProperty( QgsSymbolLayer::PropertyStrokeWidth ) )
{
fill->dataDefinedProperties().setProperty( QgsSymbolLayer::PropertyStrokeWidth, properties.property( QgsPalLayerSettings::ShapeStrokeWidth ) );
properties.setProperty( QgsPalLayerSettings::ShapeStrokeWidth, QgsProperty() );
}

if ( properties.hasProperty( QgsPalLayerSettings::ShapeJoinStyle ) &&
!fill->dataDefinedProperties().hasProperty( QgsSymbolLayer::PropertyJoinStyle ) )
{
fill->dataDefinedProperties().setProperty( QgsSymbolLayer::PropertyJoinStyle, properties.property( QgsPalLayerSettings::ShapeJoinStyle ) );
properties.setProperty( QgsPalLayerSettings::ShapeJoinStyle, QgsProperty() );
}
}
}

void QgsTextBackgroundSettings::updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties )
{
if ( properties.isActive( QgsPalLayerSettings::ShapeDraw ) )
Expand Down Expand Up @@ -763,6 +885,8 @@ void QgsTextBackgroundSettings::updateDataDefinedProperties( QgsRenderContext &c
d->opacity = properties.value( QgsPalLayerSettings::ShapeOpacity, context.expressionContext(), d->opacity * 100 ).toDouble() / 100.0;
}

// for non-SVG background types, those data defined properties will not having an impact,
// instead use data defined properties within symbols
if ( properties.isActive( QgsPalLayerSettings::ShapeFillColor ) )
{
context.expressionContext().setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( d->fillColor ) );
Expand Down Expand Up @@ -818,5 +942,9 @@ QSet<QString> QgsTextBackgroundSettings::referencedFields( const QgsRenderContex
{
fields.unite( d->markerSymbol->usedAttributes( context ) );
}
if ( d->fillSymbol )
{
fields.unite( d->fillSymbol->usedAttributes( context ) );
}
return fields;
}

0 comments on commit c27e22f

Please sign in to comment.