Skip to content

Commit f524c80

Browse files
committedNov 7, 2017
More shape porting
1 parent cf7714b commit f524c80

File tree

10 files changed

+284
-0
lines changed

10 files changed

+284
-0
lines changed
 

‎python/core/layout/qgslayoutitemshape.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class QgsLayoutItemShape : QgsLayoutItem
3434
:rtype: QgsFillSymbol
3535
%End
3636

37+
virtual QRectF boundingRect() const;
38+
39+
3740
protected:
3841

3942
explicit QgsLayoutItemShape( QgsLayout *layout );

‎src/core/layout/qgslayoutitemshape.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "qgslayoutitemshape.h"
1818
#include "qgslayout.h"
1919
#include "qgslayoututils.h"
20+
#include "qgssymbollayerutils.h"
2021

2122
#include <QPainter>
2223

@@ -33,6 +34,38 @@ QgsLayoutItemShape::QgsLayoutItemShape( QgsLayout *layout )
3334
properties.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
3435
properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
3536
mShapeStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
37+
refreshSymbol();
38+
39+
connect( this, &QgsLayoutItemShape::sizePositionChanged, this, [ = ]
40+
{
41+
updateBoundingRect();
42+
update();
43+
} );
44+
}
45+
46+
void QgsLayoutItemShape::refreshSymbol()
47+
{
48+
if ( layout() )
49+
{
50+
QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( layout(), nullptr, layout()->context().dpi() );
51+
mMaxSymbolBleed = ( 25.4 / layout()->context().dpi() ) * QgsSymbolLayerUtils::estimateMaxSymbolBleed( mShapeStyleSymbol.get(), rc );
52+
}
53+
54+
updateBoundingRect();
55+
56+
update();
57+
emit frameChanged();
58+
}
59+
60+
void QgsLayoutItemShape::updateBoundingRect()
61+
{
62+
QRectF rectangle = rect();
63+
rectangle.adjust( -mMaxSymbolBleed, -mMaxSymbolBleed, mMaxSymbolBleed, mMaxSymbolBleed );
64+
if ( rectangle != mCurrentRectangle )
65+
{
66+
prepareGeometryChange();
67+
mCurrentRectangle = rectangle;
68+
}
3669
}
3770

3871
void QgsLayoutItemShape::setSymbol( QgsFillSymbol *symbol )
@@ -41,6 +74,12 @@ void QgsLayoutItemShape::setSymbol( QgsFillSymbol *symbol )
4174
return;
4275

4376
mShapeStyleSymbol.reset( symbol->clone() );
77+
refreshSymbol();
78+
}
79+
80+
QRectF QgsLayoutItemShape::boundingRect() const
81+
{
82+
return mCurrentRectangle;
4483
}
4584

4685
//

‎src/core/layout/qgslayoutitemshape.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,35 @@ class CORE_EXPORT QgsLayoutItemShape : public QgsLayoutItem
4848
*/
4949
QgsFillSymbol *symbol() { return mShapeStyleSymbol.get(); }
5050

51+
// Depending on the symbol style, the bounding rectangle can be larger than the shape
52+
QRectF boundingRect() const override;
53+
5154
protected:
5255

5356
/**
5457
* Constructor for QgsLayoutItemShape, with the specified parent \a layout.
5558
*/
5659
explicit QgsLayoutItemShape( QgsLayout *layout );
5760

61+
private slots:
62+
63+
/**
64+
* Should be called after the shape's symbol is changed. Redraws the shape and recalculates
65+
* its selection bounds.
66+
*/
67+
void refreshSymbol();
68+
69+
//! Updates the bounding rect of this item
70+
void updateBoundingRect();
71+
5872
private:
5973
std::unique_ptr< QgsFillSymbol > mShapeStyleSymbol;
74+
75+
double mMaxSymbolBleed = 0.0;
76+
//! Current bounding rectangle of shape
77+
QRectF mCurrentRectangle;
78+
79+
6080
};
6181

6282

‎tests/src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ SET(TESTS
138138
testqgslayoutmodel.cpp
139139
testqgslayoutobject.cpp
140140
testqgslayoutpage.cpp
141+
testqgslayoutshapes.cpp
141142
testqgslayoutunits.cpp
142143
testqgslayoututils.cpp
143144
testqgslegendrenderer.cpp
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/***************************************************************************
2+
testqgslayoutshapes.cpp
3+
----------------------
4+
begin : October 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson at gmail.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsapplication.h"
19+
#include "qgslayout.h"
20+
#include "qgsmultirenderchecker.h"
21+
#include "qgslayoutitemshape.h"
22+
#include "qgsmapsettings.h"
23+
#include "qgsproject.h"
24+
#include "qgssymbol.h"
25+
#include "qgssinglesymbolrenderer.h"
26+
#include "qgsfillsymbollayer.h"
27+
#include <QObject>
28+
#include "qgstest.h"
29+
#include <QColor>
30+
#include <QPainter>
31+
32+
class TestQgsLayoutShapes : public QObject
33+
{
34+
Q_OBJECT
35+
36+
public:
37+
TestQgsLayoutShapes() = default;
38+
39+
private slots:
40+
void initTestCase();// will be called before the first testfunction is executed.
41+
void cleanupTestCase();// will be called after the last testfunction was executed.
42+
void init();// will be called before each testfunction is executed.
43+
void cleanup();// will be called after every testfunction.
44+
void rectangle(); //test if rectangle shape is functioning
45+
void triangle(); //test if triange shape is functioning
46+
void ellipse(); //test if ellipse shape is functioning
47+
void roundedRectangle(); //test if rounded rectangle shape is functioning
48+
void symbol(); //test is styling shapes via symbol is working
49+
50+
private:
51+
52+
QString mReport;
53+
};
54+
55+
void TestQgsLayoutShapes::initTestCase()
56+
{
57+
QgsApplication::init();
58+
QgsApplication::initQgis();
59+
60+
mReport = QStringLiteral( "<h1>Composer Shape Tests</h1>\n" );
61+
}
62+
63+
void TestQgsLayoutShapes::cleanupTestCase()
64+
{
65+
QString myReportFile = QDir::tempPath() + "/qgistest.html";
66+
QFile myFile( myReportFile );
67+
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
68+
{
69+
QTextStream myQTextStream( &myFile );
70+
myQTextStream << mReport;
71+
myFile.close();
72+
}
73+
QgsApplication::exitQgis();
74+
}
75+
76+
void TestQgsLayoutShapes::init()
77+
{
78+
79+
}
80+
81+
void TestQgsLayoutShapes::cleanup()
82+
{
83+
84+
}
85+
86+
void TestQgsLayoutShapes::rectangle()
87+
{
88+
QgsProject p;
89+
QgsLayout l( &p );
90+
l.initializeDefaults();
91+
92+
QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
93+
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
94+
shape->attemptResize( QgsLayoutSize( 150, 100 ) );
95+
96+
97+
QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
98+
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
99+
fillSymbol->changeSymbolLayer( 0, simpleFill );
100+
simpleFill->setColor( QColor( 255, 150, 0 ) );
101+
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
102+
simpleFill->setStrokeWidth( 0.3 );
103+
simpleFill->setPenJoinStyle( Qt::MiterJoin );
104+
shape->setSymbol( fillSymbol.get() );
105+
106+
l.addLayoutItem( shape );
107+
108+
QgsLayoutChecker checker( QStringLiteral( "composershapes_rectangle" ), &l );
109+
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
110+
QVERIFY( checker.testLayout( mReport ) );
111+
}
112+
113+
void TestQgsLayoutShapes::triangle()
114+
{
115+
QgsProject p;
116+
QgsLayout l( &p );
117+
l.initializeDefaults();
118+
119+
QgsLayoutItemTriangleShape *shape = new QgsLayoutItemTriangleShape( &l );
120+
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
121+
shape->attemptResize( QgsLayoutSize( 150, 100 ) );
122+
123+
124+
QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
125+
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
126+
fillSymbol->changeSymbolLayer( 0, simpleFill );
127+
simpleFill->setColor( QColor( 255, 150, 0 ) );
128+
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
129+
simpleFill->setStrokeWidth( 0.3 );
130+
simpleFill->setPenJoinStyle( Qt::MiterJoin );
131+
shape->setSymbol( fillSymbol.get() );
132+
133+
l.addLayoutItem( shape );
134+
135+
QgsLayoutChecker checker( QStringLiteral( "composershapes_triangle" ), &l );
136+
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
137+
QVERIFY( checker.testLayout( mReport ) );
138+
}
139+
140+
void TestQgsLayoutShapes::ellipse()
141+
{
142+
QgsProject p;
143+
QgsLayout l( &p );
144+
l.initializeDefaults();
145+
146+
QgsLayoutItemEllipseShape *shape = new QgsLayoutItemEllipseShape( &l );
147+
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
148+
shape->attemptResize( QgsLayoutSize( 150, 100 ) );
149+
150+
QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
151+
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
152+
fillSymbol->changeSymbolLayer( 0, simpleFill );
153+
simpleFill->setColor( QColor( 255, 150, 0 ) );
154+
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
155+
simpleFill->setStrokeWidth( 0.3 );
156+
simpleFill->setPenJoinStyle( Qt::MiterJoin );
157+
shape->setSymbol( fillSymbol.get() );
158+
159+
l.addLayoutItem( shape );
160+
161+
QgsLayoutChecker checker( QStringLiteral( "composershapes_ellipse" ), &l );
162+
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
163+
QVERIFY( checker.testLayout( mReport ) );
164+
}
165+
166+
void TestQgsLayoutShapes::roundedRectangle()
167+
{
168+
QgsProject p;
169+
QgsLayout l( &p );
170+
l.initializeDefaults();
171+
172+
QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
173+
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
174+
shape->attemptResize( QgsLayoutSize( 150, 100 ) );
175+
176+
QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
177+
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
178+
fillSymbol->changeSymbolLayer( 0, simpleFill );
179+
simpleFill->setColor( QColor( 255, 150, 0 ) );
180+
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
181+
simpleFill->setStrokeWidth( 0.3 );
182+
simpleFill->setPenJoinStyle( Qt::MiterJoin );
183+
shape->setSymbol( fillSymbol.get() );
184+
185+
l.addLayoutItem( shape );
186+
187+
shape->setCornerRadius( QgsLayoutMeasurement( 30 ) );
188+
189+
QgsLayoutChecker checker( QStringLiteral( "composershapes_roundedrect" ), &l );
190+
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
191+
QVERIFY( checker.testLayout( mReport ) );
192+
}
193+
194+
void TestQgsLayoutShapes::symbol()
195+
{
196+
QgsProject p;
197+
QgsLayout l( &p );
198+
l.initializeDefaults();
199+
200+
QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
201+
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
202+
shape->attemptResize( QgsLayoutSize( 150, 100 ) );
203+
204+
//setup simple fill
205+
QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
206+
QgsFillSymbol *fillSymbol = new QgsFillSymbol();
207+
fillSymbol->changeSymbolLayer( 0, simpleFill );
208+
simpleFill->setColor( Qt::green );
209+
simpleFill->setStrokeColor( Qt::yellow );
210+
simpleFill->setStrokeWidth( 6 );
211+
shape->setSymbol( fillSymbol );
212+
delete fillSymbol;
213+
214+
l.addLayoutItem( shape );
215+
QgsLayoutChecker checker( QStringLiteral( "composershapes_symbol" ), &l );
216+
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
217+
QVERIFY( checker.testLayout( mReport ) );
218+
}
219+
220+
QGSTEST_MAIN( TestQgsLayoutShapes )
221+
#include "testqgslayoutshapes.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.