Skip to content

Commit

Permalink
[feature] Allow pen cap style to be set for simple marker symbol layers
Browse files Browse the repository at this point in the history
This is useful for the stroke-only symbols like the cross and arrowhead
markers, where it's sometimes nice to have round caps instead of square
caps.
  • Loading branch information
nyalldawson committed Mar 17, 2021
1 parent b5a7820 commit 109f95b
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 9 deletions.
34 changes: 34 additions & 0 deletions python/core/auto_generated/symbology/qgsmarkersymbollayer.sip.in
Expand Up @@ -333,6 +333,8 @@ Returns the marker's stroke join style (e.g., miter, bevel, etc).

.. seealso:: :py:func:`setPenJoinStyle`

.. seealso:: :py:func:`penCapStyle`

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

.. seealso:: :py:func:`strokeStyle`
Expand All @@ -348,11 +350,43 @@ Sets the marker's stroke join style (e.g., miter, bevel, etc).

.. seealso:: :py:func:`penJoinStyle`

.. seealso:: :py:func:`setPenCapStyle`

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

.. seealso:: :py:func:`setStrokeStyle`

.. versionadded:: 2.16
%End

Qt::PenCapStyle penCapStyle() const;
%Docstring
Returns the marker's stroke cap style (e.g., flat, round, etc).

.. seealso:: :py:func:`setPenCapStyle`

.. seealso:: :py:func:`penJoinStyle`

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

.. seealso:: :py:func:`strokeStyle`

.. versionadded:: 3.20
%End

void setPenCapStyle( Qt::PenCapStyle style );
%Docstring
Sets the marker's stroke cap ``style`` (e.g., flat, round, etc).

.. seealso:: :py:func:`penCapStyle`

.. seealso:: :py:func:`penJoinStyle`

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

.. seealso:: :py:func:`setStrokeStyle`

.. versionadded:: 3.20
%End

double strokeWidth() const;
Expand Down
18 changes: 18 additions & 0 deletions src/core/symbology/qgsmarkersymbollayer.cpp
Expand Up @@ -894,6 +894,11 @@ QgsSymbolLayer *QgsSimpleMarkerSymbolLayer::create( const QVariantMap &props )
m->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( props[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
}

if ( props.contains( QStringLiteral( "cap_style" ) ) )
{
m->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( props[QStringLiteral( "cap_style" )].toString() ) );
}

m->restoreOldDataDefinedProperties( props );

return m;
Expand All @@ -918,6 +923,7 @@ void QgsSimpleMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
mBrush = QBrush( brushColor );
mPen = QPen( penColor );
mPen.setStyle( mStrokeStyle );
mPen.setCapStyle( mPenCapStyle );
mPen.setJoinStyle( mPenJoinStyle );
mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );

Expand Down Expand Up @@ -1113,6 +1119,16 @@ void QgsSimpleMarkerSymbolLayer::draw( QgsSymbolRenderContext &context, QgsSimpl
mSelPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( style ) );
}
}
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCapStyle ) )
{
context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle ) );
QString style = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCapStyle, context.renderContext().expressionContext(), QString(), &ok );
if ( ok )
{
mPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
mSelPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
}
}

if ( shapeIsFilled( shape ) )
{
Expand Down Expand Up @@ -1183,6 +1199,7 @@ QVariantMap QgsSimpleMarkerSymbolLayer::properties() const
map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
map[QStringLiteral( "cap_style" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
return map;
Expand All @@ -1202,6 +1219,7 @@ QgsSimpleMarkerSymbolLayer *QgsSimpleMarkerSymbolLayer::clone() const
m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
m->setVerticalAnchorPoint( mVerticalAnchorPoint );
m->setPenCapStyle( mPenCapStyle );
copyDataDefinedProperties( m );
copyPaintEffect( m );
return m;
Expand Down
24 changes: 24 additions & 0 deletions src/core/symbology/qgsmarkersymbollayer.h
Expand Up @@ -299,6 +299,7 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayer : public QgsSimpleMarkerSymbolLayer
/**
* Returns the marker's stroke join style (e.g., miter, bevel, etc).
* \see setPenJoinStyle()
* \see penCapStyle()
* \see strokeColor()
* \see strokeStyle()
* \since QGIS 2.16
Expand All @@ -309,12 +310,33 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayer : public QgsSimpleMarkerSymbolLayer
* Sets the marker's stroke join style (e.g., miter, bevel, etc).
* \param style join style
* \see penJoinStyle()
* \see setPenCapStyle()
* \see setStrokeColor()
* \see setStrokeStyle()
* \since QGIS 2.16
*/
void setPenJoinStyle( Qt::PenJoinStyle style ) { mPenJoinStyle = style; }

/**
* Returns the marker's stroke cap style (e.g., flat, round, etc).
* \see setPenCapStyle()
* \see penJoinStyle()
* \see strokeColor()
* \see strokeStyle()
* \since QGIS 3.20
*/
Qt::PenCapStyle penCapStyle() const { return mPenCapStyle; }

/**
* Sets the marker's stroke cap \a style (e.g., flat, round, etc).
* \see penCapStyle()
* \see penJoinStyle()
* \see setStrokeColor()
* \see setStrokeStyle()
* \since QGIS 3.20
*/
void setPenCapStyle( Qt::PenCapStyle style ) { mPenCapStyle = style; }

/**
* Returns the width of the marker's stroke.
* \see setStrokeWidth()
Expand Down Expand Up @@ -394,6 +416,8 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayer : public QgsSimpleMarkerSymbolLayer
QgsMapUnitScale mStrokeWidthMapUnitScale;
//! Stroke pen join style
Qt::PenJoinStyle mPenJoinStyle;
//! Stroke pen cap style
Qt::PenCapStyle mPenCapStyle = Qt::SquareCap;
//! QPen corresponding to marker's stroke style
QPen mPen;
//! QBrush corresponding to marker's fill style
Expand Down
11 changes: 11 additions & 0 deletions src/gui/symbology/qgssymbollayerwidget.cpp
Expand Up @@ -651,6 +651,7 @@ QgsSimpleMarkerSymbolLayerWidget::QgsSimpleMarkerSymbolLayerWidget( QgsVectorLay
connect( btnChangeColorStroke, &QgsColorButton::colorChanged, this, &QgsSimpleMarkerSymbolLayerWidget::setColorStroke );
connect( btnChangeColorFill, &QgsColorButton::colorChanged, this, &QgsSimpleMarkerSymbolLayerWidget::setColorFill );
connect( cboJoinStyle, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsSimpleMarkerSymbolLayerWidget::penJoinStyleChanged );
connect( cboCapStyle, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsSimpleMarkerSymbolLayerWidget::penCapStyleChanged );
connect( spinSize, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleMarkerSymbolLayerWidget::setSize );
connect( spinAngle, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleMarkerSymbolLayerWidget::setAngle );
connect( spinOffsetX, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleMarkerSymbolLayerWidget::setOffset );
Expand Down Expand Up @@ -698,6 +699,9 @@ void QgsSimpleMarkerSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
cboJoinStyle->blockSignals( true );
cboJoinStyle->setPenJoinStyle( mLayer->penJoinStyle() );
cboJoinStyle->blockSignals( false );
cboCapStyle->blockSignals( true );
cboCapStyle->setPenCapStyle( mLayer->penCapStyle() );
cboCapStyle->blockSignals( false );

// without blocking signals the value gets changed because of slot setOffset()
spinOffsetX->blockSignals( true );
Expand Down Expand Up @@ -734,6 +738,7 @@ void QgsSimpleMarkerSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
registerDataDefinedButton( mStrokeWidthDDBtn, QgsSymbolLayer::PropertyStrokeWidth );
registerDataDefinedButton( mStrokeStyleDDBtn, QgsSymbolLayer::PropertyStrokeStyle );
registerDataDefinedButton( mJoinStyleDDBtn, QgsSymbolLayer::PropertyJoinStyle );
registerDataDefinedButton( mCapStyleDDBtn, QgsSymbolLayer::PropertyCapStyle );
registerDataDefinedButton( mSizeDDBtn, QgsSymbolLayer::PropertySize );
registerDataDefinedButton( mAngleDDBtn, QgsSymbolLayer::PropertyAngle );
registerDataDefinedButton( mOffsetDDBtn, QgsSymbolLayer::PropertyOffset );
Expand Down Expand Up @@ -773,6 +778,12 @@ void QgsSimpleMarkerSymbolLayerWidget::penJoinStyleChanged()
emit changed();
}

void QgsSimpleMarkerSymbolLayerWidget::penCapStyleChanged()
{
mLayer->setPenCapStyle( cboCapStyle->penCapStyle() );
emit changed();
}

void QgsSimpleMarkerSymbolLayerWidget::setSize()
{
mLayer->setSize( spinSize->value() );
Expand Down
1 change: 1 addition & 0 deletions src/gui/symbology/qgssymbollayerwidget.h
Expand Up @@ -233,6 +233,7 @@ class GUI_EXPORT QgsSimpleMarkerSymbolLayerWidget : public QgsSymbolLayerWidget,
void setShape();
void updateAssistantSymbol();
void penJoinStyleChanged();
void penCapStyleChanged();

private:

Expand Down
45 changes: 36 additions & 9 deletions src/ui/symbollayer/widget_simplemarker.ui
Expand Up @@ -503,31 +503,51 @@
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Cap style</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="QgsPenCapStyleComboBox" name="cboCapStyle"/>
</item>
<item row="10" column="4">
<widget class="QgsPropertyOverrideButton" name="mCapStyleDDBtn">
<property name="text">
<string>…</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsColorButton</class>
<extends>QToolButton</extends>
<header>qgscolorbutton.h</header>
<container>1</container>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>qgsdoublespinbox.h</header>
</customwidget>
<customwidget>
<class>QgsPropertyOverrideButton</class>
<extends>QToolButton</extends>
<header>qgspropertyoverridebutton.h</header>
</customwidget>
<customwidget>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>qgsdoublespinbox.h</header>
</customwidget>
<customwidget>
<class>QgsUnitSelectionWidget</class>
<extends>QWidget</extends>
<header>qgsunitselectionwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsColorButton</class>
<extends>QToolButton</extends>
<header>qgscolorbutton.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsPenJoinStyleComboBox</class>
<extends>QComboBox</extends>
Expand All @@ -538,6 +558,11 @@
<extends>QComboBox</extends>
<header>qgspenstylecombobox.h</header>
</customwidget>
<customwidget>
<class>QgsPenCapStyleComboBox</class>
<extends>QComboBox</extends>
<header>qgspenstylecombobox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>spinSize</tabstop>
Expand All @@ -554,6 +579,8 @@
<tabstop>mStrokeWidthDDBtn</tabstop>
<tabstop>cboJoinStyle</tabstop>
<tabstop>mJoinStyleDDBtn</tabstop>
<tabstop>cboCapStyle</tabstop>
<tabstop>mCapStyleDDBtn</tabstop>
<tabstop>spinAngle</tabstop>
<tabstop>mAngleDDBtn</tabstop>
<tabstop>spinOffsetX</tabstop>
Expand Down
14 changes: 14 additions & 0 deletions tests/src/core/testqgssimplemarker.cpp
Expand Up @@ -78,6 +78,7 @@ class TestQgsSimpleMarkerSymbol : public QObject
void simpleMarkerSymbolBevelJoin();
void simpleMarkerSymbolMiterJoin();
void simpleMarkerSymbolRoundJoin();
void simpleMarkerSymbolCapStyle();
void simpleMarkerOctagon();
void simpleMarkerSquareWithCorners();
void simpleMarkerAsterisk();
Expand Down Expand Up @@ -308,6 +309,19 @@ void TestQgsSimpleMarkerSymbol::simpleMarkerSymbolRoundJoin()
QVERIFY( imageCheck( "simplemarker_roundjoin" ) );
}

void TestQgsSimpleMarkerSymbol::simpleMarkerSymbolCapStyle()
{
mReport += QLatin1String( "<h2>Cap style</h2>\n" );

mSimpleMarkerLayer->setColor( Qt::blue );
mSimpleMarkerLayer->setStrokeColor( Qt::black );
mSimpleMarkerLayer->setShape( QgsSimpleMarkerSymbolLayerBase::ArrowHead );
mSimpleMarkerLayer->setSize( 25 );
mSimpleMarkerLayer->setStrokeWidth( 3 );
mSimpleMarkerLayer->setPenCapStyle( Qt::RoundCap );
QVERIFY( imageCheck( "simplemarker_roundcap" ) );
}

void TestQgsSimpleMarkerSymbol::simpleMarkerOctagon()
{
mReport += QLatin1String( "<h2>Simple marker octagon</h2>\n" );
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 109f95b

Please sign in to comment.