QGIS/src/core/qgslegendrenderer.h
2019-01-10 19:54:26 +10:00

300 lines
10 KiB
C++

/***************************************************************************
qgslegendrenderer.h
--------------------------------------
Date : July 2014
Copyright : (C) 2014 by Martin Dobias
Email : wonder dot sk at gmail dot 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. *
* *
***************************************************************************/
#ifndef QGSLEGENDRENDERER_H
#define QGSLEGENDRENDERER_H
#include "qgis_core.h"
#include <QPointF>
class QRectF;
class QStandardItem;
class QgsLayerTreeGroup;
class QgsLayerTreeLayer;
class QgsLayerTreeModel;
class QgsLayerTreeModelLegendNode;
class QgsLayerTreeNode;
class QgsSymbol;
class QgsRenderContext;
#include "qgslegendsettings.h"
/**
* \ingroup core
* \brief The QgsLegendRenderer class handles automatic layout and rendering of legend.
* The content is given by QgsLayerTreeModel instance. Various layout properties can be configured
* within QgsLegendRenderer.
*
* All spacing and sizes are in millimeters.
*
* \since QGIS 2.6
*/
class CORE_EXPORT QgsLegendRenderer
{
public:
/**
* Constructor for QgsLegendRenderer. The ownership of the legend model is not changed,
* and the model must exist for the lifetime of this renderer.
*/
QgsLegendRenderer( QgsLayerTreeModel *legendModel, const QgsLegendSettings &settings );
/**
* Runs the layout algorithm and returns the minimum size required for the legend.
* \see setLegendSize()
* \see legendSize()
*/
QSizeF minimumSize();
/**
* Sets the preferred resulting legend size.
*
* If the size is null, the legend will be drawn with the minimum possible size to fit its content.
*
* \see legendSize()
* \see minimumSize()
*/
void setLegendSize( QSizeF s ) { mLegendSize = s; }
/**
* Returns the preferred legend size set by the client.
*
* If the returned size is null, the legend will be drawn with the minimum possible size to fit its content.
*
* \see minimumSize()
* \see setLegendSize()
*/
QSizeF legendSize() const { return mLegendSize; }
/**
* Draws the legend with given \a painter. The legend will occupy the area reported in legendSize().
* The \a painter should be scaled beforehand so that units correspond to millimeters.
*/
void drawLegend( QPainter *painter );
/**
* Draws the legend using a given render \a context. The legend will occupy the area reported in legendSize().
*
* \since QGIS 3.6
*/
void drawLegend( QgsRenderContext &context );
/**
* Sets the \a style of a \a node.
*
* \see nodeLegendStyle()
*/
static void setNodeLegendStyle( QgsLayerTreeNode *node, QgsLegendStyle::Style style );
/**
* Returns the style for the given \a node, within the specified \a model.
*
* \see setNodeLegendStyle()
*/
static QgsLegendStyle::Style nodeLegendStyle( QgsLayerTreeNode *node, QgsLayerTreeModel *model );
private:
#ifndef SIP_RUN
/**
* A legend Nucleon is either a group title, a layer title or a layer child item.
*
* E.g. a layer title nucleon is just the layer's title, it does not
* include all of that layer's subitems. Similarly, a group's title nucleon is just
* the group title, and does not include the actual content of that group.
*/
class Nucleon
{
public:
//! Constructor for Nuclean
Nucleon() = default;
QObject *item = nullptr;
//! Symbol size, not including any preset padding space around the symbol
QSizeF symbolSize;
//! Label size, not including any preset padding space around the label
QSizeF labelSize;
//! Nucleon size
QSizeF size;
/**
* Horizontal offset for the symbol label.
*
* This offset is the same for all symbol labels belonging to the same layer,
* within the same legend column.
*/
double labelXOffset = 0.0;
};
/**
* An Atom is indivisible set of legend Nucleons (i.e. it is indivisible into more columns).
*
* An Atom may consist of one or more Nucleon(s), depending on the layer splitting mode:
*
* 1) no layer split: [group_title ...] layer_title layer_item [layer_item ...]
* 2) layer split: [group_title ...] layer_title layer_item
* or: layer_item
*
* This means that group titles must not be split from layer titles and layer titles
* must not be split from the first layer item, because this results in a poor layout
* and it would not be logical to leave a group or layer title at the bottom of a column,
* separated from the actual content of that group or layer.
*/
class Atom
{
public:
Atom();
//! List of child Nucleons belonging to this Atom.
QList<Nucleon> nucleons;
//! Atom size, including internal spacing between Nucleons, but excluding any padding space around the Atom itself.
QSizeF size = QSizeF( 0, 0 );
//! Corresponding column index
int column = 0;
};
/**
* Draws the legend and returns the actual size of the legend.
*
* If \a painter is nullptr, only the size of the legend will be calculated and no
* painting will be attempted.
*/
QSizeF paintAndDetermineSize( QPainter *painter = nullptr );
/**
* Returns a list of Atoms for the specified \a parentGroup, respecting the current layer's
* splitting settings.
*/
QList<Atom> createAtomList( QgsLayerTreeGroup *parentGroup, bool splitLayer );
/**
* Divides a list of Atoms into columns, and sets the column index for each atom in the list.
*/
void setColumns( QList<Atom> &atomList );
/**
* Draws a title in the legend using the title font and the specified alignment settings.
*
* Returns the size required to draw the complete title.
*
* If \a painter is nullptr, no painting will be attempted, but the required size will still be calculated and returned.
*/
QSizeF drawTitle( QPainter *painter = nullptr, QPointF point = QPointF(), Qt::AlignmentFlag halignment = Qt::AlignLeft, double legendWidth = 0 );
/**
* Returns the calculated padding space required above the given \a atom.
*/
double spaceAboveAtom( const Atom &atom );
/**
* Draws an \a atom and return its actual size.
*
* The \a atom is drawn with the space above it, so that the first atoms in column are all
* aligned to the same line regardless of their style top spacing.
*/
QSizeF drawAtom( const Atom &atom, QPainter *painter = nullptr, QPointF point = QPointF() );
/**
* Draws the symbol of a given symbol QgsLayerTreeModelLegendNode.
*/
Nucleon drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, QPainter *painter = nullptr, QPointF point = QPointF(), double labelXOffset = 0 );
/**
* Draws the title of a layer, given a QgsLayerTreeLayer, and a destination \a painter.
*
* Returns the size of the title.
*
* The \a painter may be nullptr, in which case on the size is calculated and no painting is attempted.
*/
QSizeF drawLayerTitle( QgsLayerTreeLayer *nodeLayer, QPainter *painter = nullptr, QPointF point = QPointF() );
/**
* Draws a group item.
* Returns the size of the title.
*/
QSizeF drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QPainter *painter = nullptr, QPointF point = QPointF() );
/**
* Draws the legend using the specified render \a context, and returns the actual size of the legend.
*
* If \a context is nullptr, only the size of the legend will be calculated and no
* painting will be attempted.
*/
QSizeF paintAndDetermineSize( QgsRenderContext *context );
/**
* Draws a title in the legend using the specified render \a context, with the title font and the specified alignment settings.
*
* Returns the size required to draw the complete title.
*
* If \a context is nullptr, no painting will be attempted, but the required size will still be calculated and returned.
*/
QSizeF drawTitle( QgsRenderContext *context, QPointF point = QPointF(), Qt::AlignmentFlag halignment = Qt::AlignLeft, double legendWidth = 0 );
/**
* Draws an \a atom and return its actual size, using the specified render \a context.
*
* The \a atom is drawn with the space above it, so that the first atoms in column are all
* aligned to the same line regardless of their style top spacing.
*
* If \a context is nullptr, no painting will be attempted, but the required size will still be calculated and returned.
*/
QSizeF drawAtom( const Atom &atom, QgsRenderContext *rendercontext, QPointF point = QPointF() );
/**
* Draws the symbol of a given symbol QgsLayerTreeModelLegendNode, using the specified render \a context.
*/
Nucleon drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, QgsRenderContext *context, QPointF point = QPointF(), double labelXOffset = 0 );
/**
* Draws the title of a layer, given a QgsLayerTreeLayer, and a destination render \a context.
*
* Returns the size of the title.
*
* The \a context may be nullptr, in which case on the size is calculated and no painting is attempted.
*/
QSizeF drawLayerTitle( QgsLayerTreeLayer *nodeLayer, QgsRenderContext *context, QPointF point = QPointF() );
/**
* Draws a group's title, using the specified render \a context.
*
* Returns the size of the title.
*/
QSizeF drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QgsRenderContext *context, QPointF point = QPointF() );
/**
* Returns the style of the given \a node.
*/
QgsLegendStyle::Style nodeLegendStyle( QgsLayerTreeNode *node );
private:
QgsLayerTreeModel *mLegendModel = nullptr;
QgsLegendSettings mSettings;
QSizeF mLegendSize;
#endif
};
#endif // QGSLEGENDRENDERER_H