QGIS API Documentation  3.9.0-Master (224899f119)
qgslayoutitemshape.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitemshape.cpp
3  -----------------------
4  begin : July 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgslayoutitemshape.h"
18 #include "qgslayout.h"
19 #include "qgslayoututils.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgslayoutmodel.h"
22 #include "qgsstyleentityvisitor.h"
23 
24 #include <QPainter>
25 
27  : QgsLayoutItem( layout )
28  , mCornerRadius( 0 )
29 {
30  setBackgroundEnabled( false );
31  setFrameEnabled( false );
32  QgsStringMap properties;
33  properties.insert( QStringLiteral( "color" ), QStringLiteral( "white" ) );
34  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
35  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
36  properties.insert( QStringLiteral( "color_border" ), QStringLiteral( "black" ) );
37  properties.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
38  properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
39  mShapeStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
40  refreshSymbol();
41 
42  connect( this, &QgsLayoutItemShape::sizePositionChanged, this, [ = ]
43  {
44  updateBoundingRect();
45  update();
46  } );
47 }
48 
50 {
51  return new QgsLayoutItemShape( layout );
52 }
53 
55 {
57 }
58 
60 {
61  switch ( mShape )
62  {
63  case Ellipse:
64  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemShapeEllipse.svg" ) );
65  case Rectangle:
66  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemShapeRectangle.svg" ) );
67  case Triangle:
68  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemShapeTriangle.svg" ) );
69  }
70 
71  return QIcon();
72 }
73 
75 {
76  if ( !id().isEmpty() )
77  {
78  return id();
79  }
80 
81  switch ( mShape )
82  {
83  case Ellipse:
84  return tr( "<Ellipse>" );
85  case Rectangle:
86  return tr( "<Rectangle>" );
87  case Triangle:
88  return tr( "<Triangle>" );
89  }
90 
91  return tr( "<Shape>" );
92 }
93 
95 {
96  if ( type == mShape )
97  {
98  return;
99  }
100 
101  mShape = type;
102 
103  if ( mLayout && id().isEmpty() )
104  {
105  //notify the model that the display name has changed
106  mLayout->itemsModel()->updateItemDisplayName( this );
107  }
108 }
109 
110 void QgsLayoutItemShape::refreshSymbol()
111 {
112  if ( layout() )
113  {
114  QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( layout(), nullptr, layout()->renderContext().dpi() );
115  mMaxSymbolBleed = ( 25.4 / layout()->renderContext().dpi() ) * QgsSymbolLayerUtils::estimateMaxSymbolBleed( mShapeStyleSymbol.get(), rc );
116  }
117 
118  updateBoundingRect();
119 
120  update();
121  emit frameChanged();
122 }
123 
124 void QgsLayoutItemShape::updateBoundingRect()
125 {
126  QRectF rectangle = rect();
127  rectangle.adjust( -mMaxSymbolBleed, -mMaxSymbolBleed, mMaxSymbolBleed, mMaxSymbolBleed );
128  if ( rectangle != mCurrentRectangle )
129  {
130  prepareGeometryChange();
131  mCurrentRectangle = rectangle;
132  }
133 }
134 
136 {
137  if ( !symbol )
138  return;
139 
140  mShapeStyleSymbol.reset( symbol->clone() );
141  refreshSymbol();
142 }
143 
145 {
146  return mCurrentRectangle;
147 }
148 
150 {
151  return mMaxSymbolBleed;
152 }
153 
155 {
156  if ( mShapeStyleSymbol )
157  {
158  QgsStyleSymbolEntity entity( mShapeStyleSymbol.get() );
159  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
160  return false;
161  }
162 
163  return true;
164 }
165 
167 {
168  QPainter *painter = context.renderContext().painter();
169  painter->setPen( Qt::NoPen );
170  painter->setBrush( Qt::NoBrush );
171 
173 
174  QPolygonF shapePolygon;
175 
176  //shapes with curves must be enlarged before conversion to QPolygonF, or
177  //the curves are approximated too much and appear jaggy
178  QTransform t = QTransform::fromScale( 100, 100 );
179  //inverse transform used to scale created polygons back to expected size
180  QTransform ti = t.inverted();
181 
182  switch ( mShape )
183  {
184  case Ellipse:
185  {
186  //create an ellipse
187  QPainterPath ellipsePath;
188  ellipsePath.addEllipse( QRectF( 0, 0, rect().width() * scale, rect().height() * scale ) );
189  QPolygonF ellipsePoly = ellipsePath.toFillPolygon( t );
190  shapePolygon = ti.map( ellipsePoly );
191  break;
192  }
193  case Rectangle:
194  {
195  //if corner radius set, then draw a rounded rectangle
196  if ( mCornerRadius.length() > 0 )
197  {
198  QPainterPath roundedRectPath;
199  double radius = mLayout->convertToLayoutUnits( mCornerRadius ) * scale;
200  roundedRectPath.addRoundedRect( QRectF( 0, 0, rect().width() * scale, rect().height() * scale ), radius, radius );
201  QPolygonF roundedPoly = roundedRectPath.toFillPolygon( t );
202  shapePolygon = ti.map( roundedPoly );
203  }
204  else
205  {
206  shapePolygon = QPolygonF( QRectF( 0, 0, rect().width() * scale, rect().height() * scale ) );
207  }
208  break;
209  }
210  case Triangle:
211  {
212  shapePolygon << QPointF( 0, rect().height() * scale );
213  shapePolygon << QPointF( rect().width() * scale, rect().height() * scale );
214  shapePolygon << QPointF( rect().width() / 2.0 * scale, 0 );
215  shapePolygon << QPointF( 0, rect().height() * scale );
216  break;
217  }
218  }
219 
220  QList<QPolygonF> rings; //empty list
221 
222  symbol()->startRender( context.renderContext() );
223  symbol()->renderPolygon( shapePolygon, &rings, nullptr, context.renderContext() );
224  symbol()->stopRender( context.renderContext() );
225 }
226 
227 bool QgsLayoutItemShape::writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const
228 {
229  element.setAttribute( QStringLiteral( "shapeType" ), mShape );
230  element.setAttribute( QStringLiteral( "cornerRadiusMeasure" ), mCornerRadius.encodeMeasurement() );
231 
232  QDomElement shapeStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mShapeStyleSymbol.get(), document, context );
233  element.appendChild( shapeStyleElem );
234 
235  return true;
236 }
237 
238 bool QgsLayoutItemShape::readPropertiesFromElement( const QDomElement &element, const QDomDocument &, const QgsReadWriteContext &context )
239 {
240  mShape = static_cast< Shape >( element.attribute( QStringLiteral( "shapeType" ), QStringLiteral( "0" ) ).toInt() );
241  if ( element.hasAttribute( QStringLiteral( "cornerRadiusMeasure" ) ) )
242  mCornerRadius = QgsLayoutMeasurement::decodeMeasurement( element.attribute( QStringLiteral( "cornerRadiusMeasure" ), QStringLiteral( "0" ) ) );
243  else
244  mCornerRadius = QgsLayoutMeasurement( element.attribute( QStringLiteral( "cornerRadius" ), QStringLiteral( "0" ) ).toDouble() );
245 
246  QDomElement shapeStyleSymbolElem = element.firstChildElement( QStringLiteral( "symbol" ) );
247  if ( !shapeStyleSymbolElem.isNull() )
248  {
249  mShapeStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( shapeStyleSymbolElem, context ) );
250  }
251 
252  return true;
253 }
QIcon icon() const override
Returns the item&#39;s icon.
void setShapeType(QgsLayoutItemShape::Shape type)
Sets the type of shape (e.g.
The class is used as a container of context for various read/write operations on other objects...
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:971
Base class for graphical items within a QgsLayout.
double estimatedFrameBleed() const override
Returns the estimated amount the item&#39;s frame bleeds outside the item&#39;s actual rectangle.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
QgsLayoutItemShape(QgsLayout *layout)
Constructor for QgsLayoutItemShape, with the specified parent layout.
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1226
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
An interface for classes which can visit style entity (e.g.
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout&#39;s render context, which stores information relating to the current ...
Definition: qgslayout.cpp:358
QMap< QString, QString > QgsStringMap
Definition: qgis.h:597
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:423
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
QString displayName() const override
Gets item display name.
void frameChanged()
Emitted if the item&#39;s frame style changes.
void sizePositionChanged()
Emitted when the item&#39;s size or position changes.
static QgsLayoutItemShape * create(QgsLayout *layout)
Returns a new shape item for the specified layout.
const QgsLayout * layout() const
Returns the layout the object is attached to.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Renders the symbol using the given render context.
Definition: qgssymbol.cpp:1948
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:2051
double dpi() const
Returns the dpi for outputting the layout.
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgslayoutitem.h:72
Layout item for basic filled shapes (e.g.
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
QPointer< QgsLayout > mLayout
int type() const override
QRectF boundingRect() const override
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
QString id() const
Returns the item&#39;s ID name.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:44
static QgsLayoutMeasurement decodeMeasurement(const QString &string)
Decodes a measurement from a string.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
double length() const
Returns the length of the measurement.
void setSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used to draw the shape.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsFillSymbol * symbol()
Returns the fill symbol used to draw the shape.
virtual QString uuid() const
Returns the item identification string.
virtual void setFrameEnabled(bool drawFrame)
Sets whether this item has a frame drawn around it or not.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1154
QString encodeMeasurement() const
Encodes the layout measurement to a string.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item&#39;s contents using the specified item render context.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:446
Contains information relating to the style entity currently being visited.