33 : mLegendModel( legendModel )
34 , mSettings( settings )
40 return paintAndDetermineSize( 0 );
45 paintAndDetermineSize( painter );
49 QSizeF QgsLegendRenderer::paintAndDetermineSize( QPainter* painter )
53 if ( !rootGroup )
return size;
55 QList<Atom> atomList = createAtomList( rootGroup, mSettings.
splitLayer() );
57 setColumns( atomList );
59 qreal maxColumnWidth = 0;
62 foreach ( Atom atom, atomList )
64 maxColumnWidth = qMax( atom.size.width(), maxColumnWidth );
69 QSizeF titleSize = drawTitle();
71 titleSize.rwidth() += mSettings.
boxSpace() * 2.0;
74 QPointF point( mSettings.
boxSpace(), columnTop );
75 bool firstInColumn =
true;
76 double columnMaxHeight = 0;
77 qreal columnWidth = 0;
79 foreach ( Atom atom, atomList )
81 if ( atom.column > column )
86 point.rx() += mSettings.
columnSpace() + maxColumnWidth;
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();
112 size.rheight() = columnTop + columnMaxHeight + mSettings.
boxSpace();
113 size.rwidth() = point.x();
114 if ( !mSettings.
title().isEmpty() )
116 size.rwidth() = qMax( titleSize.width(), size.width() );
120 if ( mLegendSize.isValid() )
122 qreal w = qMax( size.width(), mLegendSize.width() );
123 qreal h = qMax( size.height(), mLegendSize.height() );
124 size = QSizeF( w, h );
128 if ( !mSettings.
title().isEmpty() )
136 point.rx() = size.width() / 2;
140 point.rx() = size.width() - mSettings.
boxSpace();
143 drawTitle( painter, point, mSettings.
titleAlignment(), size.width() );
150 QList<QgsLegendRenderer::Atom> QgsLegendRenderer::createAtomList(
QgsLayerTreeGroup* parentGroup,
bool splitLayer )
154 if ( !parentGroup )
return atoms;
163 QList<Atom> groupAtoms = createAtomList( nodeGroup, splitLayer );
169 nucleon.size = drawGroupTitle( nodeGroup );
171 if ( groupAtoms.size() > 0 )
174 groupAtoms[0].size.rheight() += spaceAboveAtom( groupAtoms[0] );
176 groupAtoms[0].nucleons.prepend( nucleon );
177 groupAtoms[0].size.rheight() += nucleon.size.height();
178 groupAtoms[0].size.rwidth() = qMax( nucleon.size.width(), groupAtoms[0].size.width() );
184 atom.nucleons.append( nucleon );
185 atom.size.rwidth() += nucleon.size.width();
186 atom.size.rheight() += nucleon.size.height();
187 atom.size.rwidth() = qMax( nucleon.size.width(), atom.size.width() );
188 groupAtoms.append( atom );
191 atoms.append( groupAtoms );
203 nucleon.size = drawLayerTitle( nodeLayer );
204 atom.nucleons.append( nucleon );
205 atom.size.rwidth() = nucleon.size.width();
206 atom.size.rheight() = nucleon.size.height();
209 QList<QgsLayerTreeModelLegendNode*> legendNodes = mLegendModel->
layerLegendNodes( nodeLayer );
217 QList<Atom> layerAtoms;
219 for (
int j = 0; j < legendNodes.count(); j++ )
223 Nucleon symbolNucleon = drawSymbolItem( legendNode );
229 atom.size.rwidth() = qMax( symbolNucleon.size.width(), atom.size.width() );
231 if ( atom.nucleons.size() > 0 )
236 atom.size.rheight() += symbolNucleon.size.height();
237 atom.nucleons.append( symbolNucleon );
242 symbolAtom.nucleons.append( symbolNucleon );
243 symbolAtom.size.rwidth() = symbolNucleon.size.width();
244 symbolAtom.size.rheight() = symbolNucleon.size.height();
245 layerAtoms.append( symbolAtom );
248 layerAtoms.prepend( atom );
249 atoms.append( layerAtoms );
257 void QgsLegendRenderer::setColumns( QList<Atom>& atomList )
262 double totalHeight = 0;
264 qreal maxAtomHeight = 0;
265 foreach ( Atom atom, atomList )
269 totalHeight += spaceAboveAtom( atom );
271 totalHeight += atom.size.height();
272 maxAtomHeight = qMax( atom.size.height(), maxAtomHeight );
282 double avgColumnHeight = totalHeight / mSettings.
columnCount();
283 int currentColumn = 0;
284 int currentColumnAtomCount = 0;
285 double currentColumnHeight = 0;
286 double maxColumnHeight = 0;
287 double closedColumnsHeight = 0;
289 for (
int i = 0; i < atomList.size(); i++ )
291 Atom atom = atomList[i];
292 double currentHeight = currentColumnHeight;
295 currentHeight += spaceAboveAtom( atom );
297 currentHeight += atom.size.height();
300 avgColumnHeight = ( totalHeight - closedColumnsHeight ) / ( mSettings.
columnCount() - currentColumn );
301 if (( currentHeight - avgColumnHeight ) > atom.size.height() / 2
302 && currentColumnAtomCount > 0
303 && currentHeight > maxAtomHeight
304 && currentHeight > maxColumnHeight
309 currentColumnAtomCount = 0;
310 closedColumnsHeight += currentColumnHeight;
311 currentColumnHeight = atom.size.height();
315 currentColumnHeight = currentHeight;
317 atomList[i].column = currentColumn;
318 currentColumnAtomCount++;
319 maxColumnHeight = qMax( currentColumnHeight, maxColumnHeight );
325 QMap<QString, qreal> maxSymbolWidth;
326 for (
int i = 0; i < atomList.size(); i++ )
328 Atom& atom = atomList[i];
329 for (
int j = 0; j < atom.nucleons.size(); j++ )
333 QString key = QString(
"%1-%2" ).arg(( qulonglong )legendNode->layerNode() ).arg( atom.column );
334 maxSymbolWidth[key] = qMax( atom.nucleons[j].symbolSize.width(), maxSymbolWidth[key] );
338 for (
int i = 0; i < atomList.size(); i++ )
340 Atom& atom = atomList[i];
341 for (
int j = 0; j < atom.nucleons.size(); j++ )
345 QString key = QString(
"%1-%2" ).arg(( qulonglong )legendNode->layerNode() ).arg( atom.column );
348 atom.nucleons[j].labelXOffset = maxSymbolWidth[key] + space;
349 atom.nucleons[j].size.rwidth() = maxSymbolWidth[key] + space + atom.nucleons[j].labelSize.width();
356 QSizeF QgsLegendRenderer::drawTitle( QPainter* painter, QPointF point, Qt::AlignmentFlag halignment,
double legendWidth )
359 if ( mSettings.
title().isEmpty() )
365 double y = point.y();
369 painter->setPen( mSettings.
fontColor() );
375 switch ( halignment )
377 case Qt::AlignHCenter:
378 textBoxWidth = ( qMin((
double ) point.x(), legendWidth - point.x() ) - mSettings.
boxSpace() ) * 2.0;
379 textBoxLeft = point.x() - textBoxWidth / 2.;
383 textBoxWidth = point.x() - mSettings.
boxSpace();
387 textBoxLeft = point.x();
388 textBoxWidth = legendWidth - point.x() - mSettings.
boxSpace();
394 for ( QStringList::Iterator titlePart = lines.begin(); titlePart != lines.end(); ++titlePart )
401 QRectF r( textBoxLeft, y, textBoxWidth, height );
405 mSettings.
drawText( painter, r, *titlePart, titleFont, halignment, Qt::AlignVCenter, Qt::TextDontClip );
409 size.rwidth() = qMax( width, size.rwidth() );
412 if ( titlePart != lines.end() )
417 size.rheight() = y - point.y();
423 double QgsLegendRenderer::spaceAboveAtom( Atom atom )
425 if ( atom.nucleons.size() == 0 )
return 0;
427 Nucleon nucleon = atom.nucleons.first();
429 if (
QgsLayerTreeGroup* nodeGroup = qobject_cast<QgsLayerTreeGroup*>( nucleon.item ) )
433 else if (
QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( nucleon.item ) )
437 else if ( qobject_cast<QgsLayerTreeModelLegendNode*>( nucleon.item ) )
448 QSizeF QgsLegendRenderer::drawAtom( Atom atom, QPainter* painter, QPointF point )
451 QSizeF size = QSizeF( atom.size );
452 foreach ( Nucleon nucleon, atom.nucleons )
454 if (
QgsLayerTreeGroup* groupItem = qobject_cast<QgsLayerTreeGroup*>( nucleon.item ) )
463 drawGroupTitle( groupItem, painter, point );
466 else if (
QgsLayerTreeLayer* layerItem = qobject_cast<QgsLayerTreeLayer*>( nucleon.item ) )
475 drawLayerTitle( layerItem, painter, point );
485 Nucleon symbolNucleon = drawSymbolItem( legendNode, painter, point, nucleon.labelXOffset );
487 size.rwidth() = qMax( symbolNucleon.size.width(), size.width() );
489 point.ry() += nucleon.size.height();
496 QgsLegendRenderer::Nucleon QgsLegendRenderer::drawSymbolItem(
QgsLayerTreeModelLegendNode* symbolItem, QPainter* painter, QPointF point,
double labelXOffset )
506 nucleon.item = symbolItem;
510 double width = qMax((
double ) im.
symbolSize.width(), labelXOffset ) + im.
labelSize.width();
512 nucleon.size = QSizeF( width, height );
517 QSizeF QgsLegendRenderer::drawLayerTitle(
QgsLayerTreeLayer* nodeLayer, QPainter* painter, QPointF point )
520 QModelIndex idx = mLegendModel->
node2index( nodeLayer );
523 if ( mLegendModel->
data( idx, Qt::DisplayRole ).toString().isEmpty() )
return size;
525 double y = point.y();
527 if ( painter ) painter->setPen( mSettings.
fontColor() );
532 for ( QStringList::Iterator layerItemPart = lines.begin(); layerItemPart != lines.end(); ++layerItemPart )
535 if ( painter ) mSettings.
drawText( painter, point.x(), y, *layerItemPart, layerFont );
537 size.rwidth() = qMax( width, size.width() );
538 if ( layerItemPart != lines.end() )
543 size.rheight() = y - point.y();
549 QSizeF QgsLegendRenderer::drawGroupTitle(
QgsLayerTreeGroup* nodeGroup, QPainter* painter, QPointF point )
552 QModelIndex idx = mLegendModel->
node2index( nodeGroup );
554 double y = point.y();
556 if ( painter ) painter->setPen( mSettings.
fontColor() );
561 for ( QStringList::Iterator groupPart = lines.begin(); groupPart != lines.end(); ++groupPart )
564 if ( painter ) mSettings.
drawText( painter, point.x(), y, *groupPart, groupFont );
566 size.rwidth() = qMax( width, size.width() );
567 if ( groupPart != lines.end() )
572 size.rheight() = y - point.y();
580 QString style = node->
customProperty(
"legend/title-style" ).toString();
581 if ( style ==
"hidden" )
583 else if ( style ==
"group" )
585 else if ( style ==
"subgroup" )
594 if ( legendNodes.count() == 1 && legendNodes[0]->isEmbeddedInParent() )
618 if ( !str.isEmpty() )
Layer tree group node serves as a container for layers and further groups.
QStringList splitStringForWrapping(QString stringToSplt) const
Splits a string using the wrap char taking into account handling empty wrap char which means no wrapp...
QList< QgsLayerTreeModelLegendNode * > layerLegendNodes(QgsLayerTreeLayer *nodeLayer)
Return list of legend nodes attached to a particular layer node.
double lineSpacing() const
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...
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
void drawLegend(QPainter *painter)
Draw the legend with given painter.
double columnSpace() const
QgsComposerLegendStyle style(QgsComposerLegendStyle::Style s) const
Returns style.
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)
double fontDescentMillimeters(const QFont &font) const
Returns the font descent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCA...
The QgsLegendSettings class stores the appearance and layout settings for legend drawing with QgsLege...
This class is a base class for nodes in a layer tree.
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.
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...
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
const QgsMapSettings * legendFilterByMap() const
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.
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...
double labelXOffset
offset from the left side where label should start
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
int equalColumnWidth() const
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the node.
Layer tree node points to a map layer.
void drawText(QPainter *p, double x, double y, const QString &text, const QFont &font) const
Draws Text.
double textWidthMillimeters(const QFont &font, const QString &text) const
Returns the font width in millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE...