33 : mLegendModel( legendModel )
34 , mSettings( settings )
40 return paintAndDetermineSize(
nullptr );
45 paintAndDetermineSize( painter );
49 QSizeF QgsLegendRenderer::paintAndDetermineSize(
QPainter* painter )
53 if ( !rootGroup )
return size;
57 setColumns( atomList );
59 qreal maxColumnWidth = 0;
62 Q_FOREACH (
const Atom& atom, atomList )
64 maxColumnWidth = qMax( atom.size.width(), maxColumnWidth );
69 QSizeF titleSize = drawTitle();
71 titleSize.rwidth() += mSettings.
boxSpace() * 2.0;
75 bool firstInColumn =
true;
76 double columnMaxHeight = 0;
77 qreal columnWidth = 0;
79 Q_FOREACH (
const Atom& atom, atomList )
81 if ( atom.column > column )
90 point.rx() += mSettings.
columnSpace() + columnWidth;
92 point.ry() = columnTop;
99 point.ry() += spaceAboveAtom( atom );
102 QSizeF atomSize = drawAtom( atom, painter, point );
103 columnWidth = qMax( atomSize.
width(), columnWidth );
105 point.ry() += atom.size.height();
106 columnMaxHeight = qMax( point.y() - columnTop, columnMaxHeight );
108 firstInColumn =
false;
110 point.rx() += columnWidth + mSettings.
boxSpace();
113 size.
rwidth() = point.x();
116 size.
rwidth() = qMax( titleSize.width(), size.
width() );
122 qreal w = qMax( size.
width(), mLegendSize.
width() );
136 point.rx() = size.
width() / 2;
154 if ( !parentGroup )
return atoms;
163 QList<Atom> groupAtoms = createAtomList( nodeGroup, splitLayer );
164 bool hasSubItems = groupAtoms.
size() > 0;
170 nucleon.size = drawGroupTitle( nodeGroup );
175 groupAtoms[0].
size.rheight() += spaceAboveAtom( groupAtoms[0] );
177 groupAtoms[0].nucleons.
prepend( nucleon );
178 groupAtoms[0].
size.rheight() += nucleon.size.height();
179 groupAtoms[0].
size.rwidth() = qMax( nucleon.size.width(), groupAtoms[0].
size.width() );
185 atom.nucleons.append( nucleon );
186 atom.size.rwidth() += nucleon.size.width();
187 atom.size.rheight() += nucleon.size.height();
188 atom.size.rwidth() = qMax( nucleon.size.width(), atom.size.width() );
189 groupAtoms.
append( atom );
195 atoms.
append( groupAtoms );
209 nucleon.size = drawLayerTitle( nodeLayer );
210 atom.nucleons.append( nucleon );
211 atom.size.rwidth() = nucleon.size.width();
212 atom.size.rheight() = nucleon.size.height();
225 for (
int j = 0; j < legendNodes.
count(); j++ )
229 Nucleon symbolNucleon = drawSymbolItem( legendNode );
235 atom.size.rwidth() = qMax( symbolNucleon.size.width(), atom.size.width() );
237 if ( !atom.nucleons.isEmpty() )
242 atom.size.rheight() += symbolNucleon.size.height();
243 atom.nucleons.append( symbolNucleon );
248 symbolAtom.nucleons.append( symbolNucleon );
249 symbolAtom.size.rwidth() = symbolNucleon.size.width();
250 symbolAtom.size.rheight() = symbolNucleon.size.height();
251 layerAtoms.
append( symbolAtom );
255 atoms.
append( layerAtoms );
263 void QgsLegendRenderer::setColumns(
QList<Atom>& atomList )
268 double totalHeight = 0;
269 qreal maxAtomHeight = 0;
270 Q_FOREACH (
const Atom& atom, atomList )
272 totalHeight += spaceAboveAtom( atom );
273 totalHeight += atom.size.height();
274 maxAtomHeight = qMax( atom.size.height(), maxAtomHeight );
282 double maxColumnHeight = 0;
283 int currentColumn = 0;
284 int currentColumnAtomCount = 0;
285 double currentColumnHeight = 0;
286 double closedColumnsHeight = 0;
288 for (
int i = 0; i < atomList.
size(); i++ )
291 double avgColumnHeight = ( totalHeight - closedColumnsHeight ) / ( mSettings.
columnCount() - currentColumn );
293 Atom atom = atomList.
at( i );
294 double currentHeight = currentColumnHeight;
295 if ( currentColumnAtomCount > 0 )
296 currentHeight += spaceAboveAtom( atom );
297 currentHeight += atom.size.height();
299 bool canCreateNewColumn = ( currentColumnAtomCount > 0 )
300 && ( currentColumn < mSettings.
columnCount() - 1 );
302 bool shouldCreateNewColumn = ( currentHeight - avgColumnHeight ) > atom.size.height() / 2
303 && currentColumnAtomCount > 0
304 && currentHeight > maxAtomHeight
305 && currentHeight > maxColumnHeight;
309 shouldCreateNewColumn |= ( atomList.
size() - i < mSettings.
columnCount() - currentColumn );
311 if ( canCreateNewColumn && shouldCreateNewColumn )
315 currentColumnAtomCount = 0;
316 closedColumnsHeight += currentColumnHeight;
317 currentColumnHeight = atom.size.height();
321 currentColumnHeight = currentHeight;
323 atomList[i].column = currentColumn;
324 currentColumnAtomCount++;
325 maxColumnHeight = qMax( currentColumnHeight, maxColumnHeight );
330 for (
int i = 0; i < atomList.
size(); i++ )
332 Atom& atom = atomList[i];
333 for (
int j = 0; j < atom.nucleons.size(); j++ )
337 QString key =
QString(
"%1-%2" ).
arg( reinterpret_cast< qulonglong >( legendNode->layerNode() ) ).
arg( atom.column );
338 maxSymbolWidth[key] = qMax( atom.nucleons.at( j ).symbolSize.width(), maxSymbolWidth[key] );
342 for (
int i = 0; i < atomList.
size(); i++ )
344 Atom& atom = atomList[i];
345 for (
int j = 0; j < atom.nucleons.size(); j++ )
349 QString key =
QString(
"%1-%2" ).
arg( reinterpret_cast< qulonglong >( legendNode->layerNode() ) ).
arg( atom.column );
352 atom.nucleons[j].labelXOffset = maxSymbolWidth[key] + space;
353 atom.nucleons[j].
size.rwidth() = maxSymbolWidth[key] + space + atom.nucleons.at( j ).labelSize.width();
360 QSizeF QgsLegendRenderer::drawTitle(
QPainter* painter,
QPointF point, Qt::AlignmentFlag halignment,
double legendWidth )
369 double y = point.
y();
379 switch ( halignment )
381 case Qt::AlignHCenter:
382 textBoxWidth = ( qMin( static_cast< double >( point.
x() ), legendWidth - point.
x() ) - mSettings.
boxSpace() ) * 2.0;
383 textBoxLeft = point.
x() - textBoxWidth / 2.;
387 textBoxWidth = point.
x() - mSettings.
boxSpace();
391 textBoxLeft = point.
x();
392 textBoxWidth = legendWidth - point.
x() - mSettings.
boxSpace();
405 QRectF r( textBoxLeft, y, textBoxWidth, height );
409 mSettings.
drawText( painter, r, *titlePart, titleFont, halignment, Qt::AlignVCenter, Qt::TextDontClip );
416 if ( titlePart != lines.
end() )
427 double QgsLegendRenderer::spaceAboveAtom(
const Atom& atom )
429 if ( atom.nucleons.isEmpty() )
return 0;
431 Nucleon nucleon = atom.nucleons.first();
433 if (
QgsLayerTreeGroup* nodeGroup = qobject_cast<QgsLayerTreeGroup*>( nucleon.item ) )
437 else if (
QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( nucleon.item ) )
441 else if ( qobject_cast<QgsLayerTreeModelLegendNode*>( nucleon.item ) )
456 Q_FOREACH (
const Nucleon& nucleon, atom.nucleons )
458 if (
QgsLayerTreeGroup* groupItem = qobject_cast<QgsLayerTreeGroup*>( nucleon.item ) )
467 drawGroupTitle( groupItem, painter, point );
470 else if (
QgsLayerTreeLayer* layerItem = qobject_cast<QgsLayerTreeLayer*>( nucleon.item ) )
479 drawLayerTitle( layerItem, painter, point );
489 Nucleon symbolNucleon = drawSymbolItem( legendNode, painter, point, nucleon.labelXOffset );
491 size.
rwidth() = qMax( symbolNucleon.size.width(), size.
width() );
493 point.
ry() += nucleon.size.height();
510 nucleon.item = symbolItem;
516 nucleon.size =
QSizeF( width, height );
529 double y = point.
y();
539 if ( painter ) mSettings.
drawText( painter, point.
x(), y, *layerItemPart, layerFont );
542 if ( layerItemPart != lines.
end() )
558 double y = point.
y();
568 if ( painter ) mSettings.
drawText( painter, point.
x(), y, *groupPart, groupFont );
571 if ( groupPart != lines.
end() )
585 if ( style ==
"hidden" )
587 else if ( style ==
"group" )
589 else if ( style ==
"subgroup" )
Layer tree group node serves as a container for layers and further groups.
void drawText(QPainter *p, double x, double y, const QString &text, const QFont &font) const
Draws Text.
QgsLayerTreeGroup * rootGroup() const
Return pointer to the root node of the layer tree. Always a non-null pointer.
double fontAscentMillimeters(const QFont &font) const
Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCAL...
void drawLegend(QPainter *painter)
Draw the legend with given painter.
QStringList splitStringForWrapping(const QString &stringToSplt) const
Splits a string using the wrap char taking into account handling empty wrap char which means no wrapp...
QgsLayerTreeModelLegendNode * legendNodeEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Return legend node that may be embbeded in parent (i.e.
const T & at(int i) const
double textWidthMillimeters(const QFont &font, const QString &text) const
Returns the font width in millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE...
QModelIndex node2index(QgsLayerTreeNode *node) const
Return index for a given node. If the node does not belong to the layer tree, the result is undefined...
QPainter * painter
Painter.
QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group. No type checking is done - use isGroup() to find out whether this operation is ...
QgsLegendRenderer(QgsLayerTreeModel *legendModel, const QgsLegendSettings &settings)
Construct legend renderer.
The QgsLayerTreeModel class is model implementation for Qt item views framework.
static void setNodeLegendStyle(QgsLayerTreeNode *node, QgsComposerLegendStyle::Style style)
int count(const T &value) const
void append(const T &value)
void setPen(const QColor &color)
The QgsLegendSettings class stores the appearance and layout settings for legend drawing with QgsLege...
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QgsComposerLegendStyle style(QgsComposerLegendStyle::Style s) const
Returns style.
This class is a base class for nodes in a layer tree.
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
QList< QgsLayerTreeNode * > children()
Get list of children of the node. Children are owned by the parent.
bool isLayer(QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
QSizeF minimumSize()
Run the layout algorithm and determine the size required for legend.
virtual ItemMetrics draw(const QgsLegendSettings &settings, ItemContext *ctx)
Entry point called from QgsLegendRenderer to do the rendering.
const QgsMapSettings * legendFilterMapSettings() const
Returns the current map settings used for the current legend filter (or null if none is enabled) ...
QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer. No type checking is done - use isLayer() to find out whether this operation is ...
QPointF point
Top-left corner of the legend item.
bool equalColumnWidth() const
double columnSpace() const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
static QgsComposerLegendStyle::Style nodeLegendStyle(QgsLayerTreeNode *node, QgsLayerTreeModel *model)
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
QList< QgsLayerTreeModelLegendNode * > layerLegendNodes(QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent=false)
Return filtered list of active legend nodes attached to a particular layer node (by default it return...
void prepend(const T &value)
double lineSpacing() const
double labelXOffset
offset from the left side where label should start
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
double fontDescentMillimeters(const QFont &font) const
Returns the font descent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCA...
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the node.
Layer tree node points to a map layer.