Skip to content

Commit

Permalink
More shape porting
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 7, 2017
1 parent cf7714b commit f524c80
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 0 deletions.
3 changes: 3 additions & 0 deletions python/core/layout/qgslayoutitemshape.sip
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class QgsLayoutItemShape : QgsLayoutItem
:rtype: QgsFillSymbol
%End

virtual QRectF boundingRect() const;


protected:

explicit QgsLayoutItemShape( QgsLayout *layout );
Expand Down
39 changes: 39 additions & 0 deletions src/core/layout/qgslayoutitemshape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "qgslayoutitemshape.h"
#include "qgslayout.h"
#include "qgslayoututils.h"
#include "qgssymbollayerutils.h"

#include <QPainter>

Expand All @@ -33,6 +34,38 @@ QgsLayoutItemShape::QgsLayoutItemShape( QgsLayout *layout )
properties.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
mShapeStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
refreshSymbol();

connect( this, &QgsLayoutItemShape::sizePositionChanged, this, [ = ]
{
updateBoundingRect();
update();
} );
}

void QgsLayoutItemShape::refreshSymbol()
{
if ( layout() )
{
QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( layout(), nullptr, layout()->context().dpi() );
mMaxSymbolBleed = ( 25.4 / layout()->context().dpi() ) * QgsSymbolLayerUtils::estimateMaxSymbolBleed( mShapeStyleSymbol.get(), rc );
}

updateBoundingRect();

update();
emit frameChanged();
}

void QgsLayoutItemShape::updateBoundingRect()
{
QRectF rectangle = rect();
rectangle.adjust( -mMaxSymbolBleed, -mMaxSymbolBleed, mMaxSymbolBleed, mMaxSymbolBleed );
if ( rectangle != mCurrentRectangle )
{
prepareGeometryChange();
mCurrentRectangle = rectangle;
}
}

void QgsLayoutItemShape::setSymbol( QgsFillSymbol *symbol )
Expand All @@ -41,6 +74,12 @@ void QgsLayoutItemShape::setSymbol( QgsFillSymbol *symbol )
return;

mShapeStyleSymbol.reset( symbol->clone() );
refreshSymbol();
}

QRectF QgsLayoutItemShape::boundingRect() const
{
return mCurrentRectangle;
}

//
Expand Down
20 changes: 20 additions & 0 deletions src/core/layout/qgslayoutitemshape.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,35 @@ class CORE_EXPORT QgsLayoutItemShape : public QgsLayoutItem
*/
QgsFillSymbol *symbol() { return mShapeStyleSymbol.get(); }

// Depending on the symbol style, the bounding rectangle can be larger than the shape
QRectF boundingRect() const override;

protected:

/**
* Constructor for QgsLayoutItemShape, with the specified parent \a layout.
*/
explicit QgsLayoutItemShape( QgsLayout *layout );

private slots:

/**
* Should be called after the shape's symbol is changed. Redraws the shape and recalculates
* its selection bounds.
*/
void refreshSymbol();

//! Updates the bounding rect of this item
void updateBoundingRect();

private:
std::unique_ptr< QgsFillSymbol > mShapeStyleSymbol;

double mMaxSymbolBleed = 0.0;
//! Current bounding rectangle of shape
QRectF mCurrentRectangle;


};


Expand Down
1 change: 1 addition & 0 deletions tests/src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ SET(TESTS
testqgslayoutmodel.cpp
testqgslayoutobject.cpp
testqgslayoutpage.cpp
testqgslayoutshapes.cpp
testqgslayoutunits.cpp
testqgslayoututils.cpp
testqgslegendrenderer.cpp
Expand Down
221 changes: 221 additions & 0 deletions tests/src/core/testqgslayoutshapes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/***************************************************************************
testqgslayoutshapes.cpp
----------------------
begin : October 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail.com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsapplication.h"
#include "qgslayout.h"
#include "qgsmultirenderchecker.h"
#include "qgslayoutitemshape.h"
#include "qgsmapsettings.h"
#include "qgsproject.h"
#include "qgssymbol.h"
#include "qgssinglesymbolrenderer.h"
#include "qgsfillsymbollayer.h"
#include <QObject>
#include "qgstest.h"
#include <QColor>
#include <QPainter>

class TestQgsLayoutShapes : public QObject
{
Q_OBJECT

public:
TestQgsLayoutShapes() = default;

private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.
void rectangle(); //test if rectangle shape is functioning
void triangle(); //test if triange shape is functioning
void ellipse(); //test if ellipse shape is functioning
void roundedRectangle(); //test if rounded rectangle shape is functioning
void symbol(); //test is styling shapes via symbol is working

private:

QString mReport;
};

void TestQgsLayoutShapes::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();

mReport = QStringLiteral( "<h1>Composer Shape Tests</h1>\n" );
}

void TestQgsLayoutShapes::cleanupTestCase()
{
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();
}

void TestQgsLayoutShapes::init()
{

}

void TestQgsLayoutShapes::cleanup()
{

}

void TestQgsLayoutShapes::rectangle()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );


QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( QColor( 255, 150, 0 ) );
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
simpleFill->setStrokeWidth( 0.3 );
simpleFill->setPenJoinStyle( Qt::MiterJoin );
shape->setSymbol( fillSymbol.get() );

l.addLayoutItem( shape );

QgsLayoutChecker checker( QStringLiteral( "composershapes_rectangle" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

void TestQgsLayoutShapes::triangle()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemTriangleShape *shape = new QgsLayoutItemTriangleShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );


QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( QColor( 255, 150, 0 ) );
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
simpleFill->setStrokeWidth( 0.3 );
simpleFill->setPenJoinStyle( Qt::MiterJoin );
shape->setSymbol( fillSymbol.get() );

l.addLayoutItem( shape );

QgsLayoutChecker checker( QStringLiteral( "composershapes_triangle" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

void TestQgsLayoutShapes::ellipse()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemEllipseShape *shape = new QgsLayoutItemEllipseShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );

QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( QColor( 255, 150, 0 ) );
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
simpleFill->setStrokeWidth( 0.3 );
simpleFill->setPenJoinStyle( Qt::MiterJoin );
shape->setSymbol( fillSymbol.get() );

l.addLayoutItem( shape );

QgsLayoutChecker checker( QStringLiteral( "composershapes_ellipse" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

void TestQgsLayoutShapes::roundedRectangle()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );

QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( QColor( 255, 150, 0 ) );
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
simpleFill->setStrokeWidth( 0.3 );
simpleFill->setPenJoinStyle( Qt::MiterJoin );
shape->setSymbol( fillSymbol.get() );

l.addLayoutItem( shape );

shape->setCornerRadius( QgsLayoutMeasurement( 30 ) );

QgsLayoutChecker checker( QStringLiteral( "composershapes_roundedrect" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

void TestQgsLayoutShapes::symbol()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );

//setup simple fill
QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
QgsFillSymbol *fillSymbol = new QgsFillSymbol();
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( Qt::green );
simpleFill->setStrokeColor( Qt::yellow );
simpleFill->setStrokeWidth( 6 );
shape->setSymbol( fillSymbol );
delete fillSymbol;

l.addLayoutItem( shape );
QgsLayoutChecker checker( QStringLiteral( "composershapes_symbol" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

QGSTEST_MAIN( TestQgsLayoutShapes )
#include "testqgslayoutshapes.moc"
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
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 f524c80

Please sign in to comment.