Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[api] Add option for setting a line symbol to use when rendering
a QgsRubberBand
  • Loading branch information
nyalldawson committed Feb 24, 2021
1 parent ad56216 commit ccaca73
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 15 deletions.
31 changes: 31 additions & 0 deletions python/gui/auto_generated/qgsrubberband.sip.in
Expand Up @@ -68,6 +68,7 @@ Creates a new RubberBand.
:param geometryType: Defines how the data should be drawn onto the screen.
:py:class:`QgsWkbTypes`.LineGeometry, :py:class:`QgsWkbTypes`.PolygonGeometry or :py:class:`QgsWkbTypes`.PointGeometry
%End
~QgsRubberBand();

void setColor( const QColor &color );
%Docstring
Expand Down Expand Up @@ -345,6 +346,36 @@ Returns the rubberband as a Geometry
virtual void updatePosition();


QgsSymbol *symbol() const;
%Docstring
Returns the symbol used for rendering the rubberband, if set.

.. seealso:: :py:func:`setSymbol`

.. versionadded:: 3.20
%End

void setSymbol( QgsSymbol *symbol /Transfer/ );
%Docstring
Sets the ``symbol`` used for rendering the rubberband.

Ownership of ``symbol`` is transferred to the rubberband.

.. warning::

Only line symbols are currently supported.

.. note::

Setting a symbol for the rubberband overrides any other appearance setting,
such as the :py:func:`~QgsRubberBand.strokeColor` or :py:func:`~QgsRubberBand.width`.


.. seealso:: :py:func:`setSymbol`

.. versionadded:: 3.20
%End

protected:

virtual void paint( QPainter *p );
Expand Down
64 changes: 49 additions & 15 deletions src/gui/qgsrubberband.cpp
Expand Up @@ -20,6 +20,9 @@
#include "qgsvectorlayer.h"
#include "qgsproject.h"
#include "qgsrectangle.h"
#include "qgssymbol.h"
#include "qgsrendercontext.h"

#include <QPainter>

QgsRubberBand::QgsRubberBand( QgsMapCanvas *mapCanvas, QgsWkbTypes::GeometryType geometryType )
Expand All @@ -43,6 +46,8 @@ QgsRubberBand::QgsRubberBand()
{
}

QgsRubberBand::~QgsRubberBand() = default;

void QgsRubberBand::setColor( const QColor &color )
{
setStrokeColor( color );
Expand Down Expand Up @@ -455,26 +460,45 @@ void QgsRubberBand::paint( QPainter *p )
shapes.append( rings );
}

int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
for ( int i = 0; i < iterations; ++i )
if ( QgsLineSymbol *lineSymbol = dynamic_cast< QgsLineSymbol * >( mSymbol.get() ) )
{
if ( i == 0 && iterations > 1 )
{
// first iteration with multi-pen painting, so use secondary pen
mSecondaryPen.setWidth( mPen.width() + 2 );
p->setBrush( Qt::NoBrush );
p->setPen( mSecondaryPen );
}
else
{
// "top" layer, use primary pen/brush
p->setBrush( mBrush );
p->setPen( mPen );
}
QgsRenderContext context( QgsRenderContext::fromQPainter( p ) );
context.setFlag( QgsRenderContext::Antialiasing, true );

lineSymbol->startRender( context );
for ( const QVector<QPolygonF> &shape : qgis::as_const( shapes ) )
{
drawShape( p, shape );
for ( const QPolygonF &ring : shape )
{
lineSymbol->renderPolyline( ring, nullptr, context );
}
}
lineSymbol->stopRender( context );
}
else
{
int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
for ( int i = 0; i < iterations; ++i )
{
if ( i == 0 && iterations > 1 )
{
// first iteration with multi-pen painting, so use secondary pen
mSecondaryPen.setWidth( mPen.width() + 2 );
p->setBrush( Qt::NoBrush );
p->setPen( mSecondaryPen );
}
else
{
// "top" layer, use primary pen/brush
p->setBrush( mBrush );
p->setPen( mPen );
}

for ( const QVector<QPolygonF> &shape : qgis::as_const( shapes ) )
{
drawShape( p, shape );
}
}
}
}
Expand Down Expand Up @@ -630,6 +654,16 @@ void QgsRubberBand::updateRect()
setRect( rect );
}

QgsSymbol *QgsRubberBand::symbol() const
{
return mSymbol.get();
}

void QgsRubberBand::setSymbol( QgsSymbol *symbol )
{
mSymbol.reset( symbol );
}

void QgsRubberBand::updatePosition()
{
// re-compute rectangle
Expand Down
27 changes: 27 additions & 0 deletions src/gui/qgsrubberband.h
Expand Up @@ -30,6 +30,7 @@

class QgsVectorLayer;
class QPaintEvent;
class QgsSymbol;

#ifdef SIP_RUN
% ModuleHeaderCode
Expand Down Expand Up @@ -132,6 +133,7 @@ class GUI_EXPORT QgsRubberBand : public QgsMapCanvasItem
* QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry or QgsWkbTypes::PointGeometry
*/
QgsRubberBand( QgsMapCanvas *mapCanvas SIP_TRANSFERTHIS, QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::LineGeometry );
~QgsRubberBand() override;

/**
* Sets the color for the rubberband.
Expand Down Expand Up @@ -385,6 +387,29 @@ class GUI_EXPORT QgsRubberBand : public QgsMapCanvasItem

void updatePosition() override;

/**
* Returns the symbol used for rendering the rubberband, if set.
*
* \see setSymbol()
* \since QGIS 3.20
*/
QgsSymbol *symbol() const;

/**
* Sets the \a symbol used for rendering the rubberband.
*
* Ownership of \a symbol is transferred to the rubberband.
*
* \warning Only line symbols are currently supported.
*
* \note Setting a symbol for the rubberband overrides any other appearance setting,
* such as the strokeColor() or width().
*
* \see setSymbol()
* \since QGIS 3.20
*/
void setSymbol( QgsSymbol *symbol SIP_TRANSFER );

protected:

/**
Expand Down Expand Up @@ -423,6 +448,8 @@ class GUI_EXPORT QgsRubberBand : public QgsMapCanvasItem
std::unique_ptr<QSvgRenderer> mSvgRenderer;
QPoint mSvgOffset;

std::unique_ptr< QgsSymbol > mSymbol;

/**
* Nested lists used for multitypes
*/
Expand Down
50 changes: 50 additions & 0 deletions tests/src/gui/testqgsrubberband.cpp
Expand Up @@ -25,6 +25,8 @@
#include <qgsvectorlayer.h>
#include <qgsrubberband.h>
#include <qgslogger.h>
#include "qgssymbol.h"
#include "qgsrenderchecker.h"

class TestQgsRubberband : public QObject
{
Expand All @@ -42,12 +44,14 @@ class TestQgsRubberband : public QObject
void testBoundingRect(); //test for #12392
void testVisibility(); //test for 12486
void testClose(); //test closing geometry
void testSymbolRender();

private:
QgsMapCanvas *mCanvas = nullptr;
QgsVectorLayer *mPolygonLayer = nullptr;
QString mTestDataDir;
QgsRubberBand *mRubberband = nullptr;
QString mReport;
};

void TestQgsRubberband::initTestCase()
Expand Down Expand Up @@ -75,6 +79,7 @@ void TestQgsRubberband::initTestCase()
mCanvas->hide();

mRubberband = nullptr;
mReport += QLatin1String( "<h1>Rubberband Tests</h1>\n" );
}

void TestQgsRubberband::cleanupTestCase()
Expand All @@ -83,6 +88,15 @@ void TestQgsRubberband::cleanupTestCase()
delete mPolygonLayer;
delete mCanvas;

QString myReportFile = QDir::tempPath() + "/qgistest.html";
QFile myFile( myReportFile );
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
{
QTextStream myQTextStream( &myFile );
myQTextStream << mReport;
myFile.close();
}

QgsApplication::exitQgis();
}

Expand Down Expand Up @@ -216,6 +230,42 @@ void TestQgsRubberband::testClose()
QCOMPARE( r.partSize( 0 ), 4 );
}

void TestQgsRubberband::testSymbolRender()
{
std::unique_ptr< QgsMapCanvas > canvas = qgis::make_unique< QgsMapCanvas >();
canvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
canvas->setFrameStyle( 0 );
canvas->resize( 600, 400 );
canvas->setExtent( QgsRectangle( 10, 30, 20, 35 ) );
canvas->show();

QgsRubberBand r( canvas.get(), QgsWkbTypes::LineGeometry );
r.addGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString( 12 32, 18 33)" ) ) );

std::unique_ptr< QgsLineSymbol > lineSymbol( QgsLineSymbol::createSimple(
{
{ QStringLiteral( "line_color" ), QStringLiteral( "#0000ff" ) },
{ QStringLiteral( "line_width" ), QStringLiteral( "3" )},
{ QStringLiteral( "capstyle" ), QStringLiteral( "round" )}
} ) );
r.setSymbol( lineSymbol.release() );

QPixmap pixmap( canvas->size() );
QPainter painter( &pixmap );
canvas->render( &painter );
painter.end();
QString destFile = QDir::tempPath() + QStringLiteral( "/rubberband_line_symbol.png" );
pixmap.save( destFile );

QgsRenderChecker checker;
checker.setControlPathPrefix( QStringLiteral( "rubberband" ) );
checker.setControlName( QStringLiteral( "expected_line_symbol" ) );
checker.setRenderedImage( destFile );
bool result = checker.compareImages( QStringLiteral( "expected_line_symbol" ) );
mReport += checker.report();
QVERIFY( result );
}


QGSTEST_MAIN( TestQgsRubberband )
#include "testqgsrubberband.moc"
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 ccaca73

Please sign in to comment.