1 /***************************************************************************
2   qgslegendsettings.h
3   --------------------------------------
4   Date                 : July 2014
5   Copyright            : (C) 2014 by Martin Dobias
6   Email                : wonder dot sk at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #ifndef QGSLEGENDSETTINGS_H
17 #define QGSLEGENDSETTINGS_H
18 
19 #include "qgis_core.h"
20 #include "qgis_sip.h"
21 #include <QColor>
22 #include <QSizeF>
23 
24 class QRectF;
25 
26 #include "qgslegendstyle.h"
27 
28 class QgsExpressionContext;
29 
30 /**
31  * \ingroup core
32  * \brief The QgsLegendSettings class stores the appearance and layout settings
33  * for legend drawing with QgsLegendRenderer. The content of the legend is given
34  * in QgsLegendModel class.
35  *
36  * \since QGIS 2.6
37  */
38 class CORE_EXPORT QgsLegendSettings
39 {
40   public:
41     QgsLegendSettings();
42 
43     /**
44      * Sets the title for the legend, which will be rendered above all legend items.
45      *
46      * \see title()
47      */
setTitle(const QString & t)48     void setTitle( const QString &t ) { mTitle = t; }
49 
50     /**
51      * Returns the title for the legend, which will be rendered above all legend items.
52      *
53      * \see setTitle()
54      */
title()55     QString title() const { return mTitle; }
56 
57     /**
58      * Returns the alignment of the legend title.
59      * \see setTitleAlignment()
60      */
titleAlignment()61     Qt::AlignmentFlag titleAlignment() const { return mTitleAlignment; }
62 
63     /**
64      * Sets the \a alignment of the legend title.
65      * \see titleAlignment()
66      */
setTitleAlignment(Qt::AlignmentFlag alignment)67     void setTitleAlignment( Qt::AlignmentFlag alignment ) { mTitleAlignment = alignment; }
68 
69     /**
70      * Returns modifiable reference to the style for a legend component.
71      *
72      * \note Not available in Python bindings.
73      */
rstyle(QgsLegendStyle::Style s)74     SIP_SKIP QgsLegendStyle &rstyle( QgsLegendStyle::Style s ) { return mStyleMap[s]; } SIP_SKIP
75 
76     /**
77      * Returns the style for a legend component.
78      *
79      * \see setStyle()
80      */
style(QgsLegendStyle::Style s)81     QgsLegendStyle style( QgsLegendStyle::Style s ) const { return mStyleMap.value( s ); }
82 
83     /**
84      * Sets the \a style for a legend component.
85      *
86      * \see style()
87      */
setStyle(QgsLegendStyle::Style s,const QgsLegendStyle & style)88     void setStyle( QgsLegendStyle::Style s, const QgsLegendStyle &style ) { mStyleMap[s] = style; }
89 
90     /**
91      * Returns the legend box space (in millimeters), which is the empty margin around the inside of the legend's
92      * rectangle.
93      *
94      * \see setBoxSpace()
95      */
boxSpace()96     double boxSpace() const {return mBoxSpace;}
97 
98     /**
99      * Sets the legend box space (in millimeters), which is the empty margin around the inside of the legend's
100      * rectangle.
101      *
102      * \see boxSpace()
103      */
setBoxSpace(double s)104     void setBoxSpace( double s ) {mBoxSpace = s;}
105 
106     /**
107      * Sets a string to use as a wrapping character.
108      *
109      * Whenever this string is encountered inside legend component text it will be automatically replaced with a new
110      * line character.
111      *
112      * \see wrapChar()
113      */
setWrapChar(const QString & t)114     void setWrapChar( const QString &t ) {mWrapChar = t;}
115 
116     /**
117      * Returns the string used as a wrapping character.
118      *
119      * Whenever this string is encountered inside legend component text it will be automatically replaced with a new
120      * line character.
121      *
122      * \see setWrapChar()
123      */
wrapChar()124     QString wrapChar() const {return mWrapChar;}
125 
126     /**
127      * Returns the margin space between adjacent columns (in millimeters).
128      *
129      * \see setColumnSpace()
130      */
columnSpace()131     double columnSpace() const {return mColumnSpace;}
132 
133     /**
134      * Sets the margin space between adjacent columns (in millimeters).
135      *
136      * \see columnSpace()
137      */
setColumnSpace(double s)138     void setColumnSpace( double s ) { mColumnSpace = s;}
139 
140     /**
141      * Returns the desired minimum number of columns to show in the legend.
142      *
143      * If legend components have forced column breaks then the actual number of columns in the rendered
144      * legend may be larger than this value.
145      *
146      * \see setColumnCount()
147      */
columnCount()148     int columnCount() const { return mColumnCount; }
149 
150     /**
151      * Sets the desired minimum number of columns to show in the legend.
152      *
153      * If legend components have forced column breaks then the actual number of columns in the rendered
154      * legend may be larger than this value.
155      *
156      * \see columnCount()
157      */
setColumnCount(int c)158     void setColumnCount( int c ) { mColumnCount = c;}
159 
160     /**
161      * Returns TRUE if layer components can be split over multiple columns.
162      *
163      * \see setSplitLayer()
164      */
splitLayer()165     bool splitLayer() const { return mSplitLayer; }
166 
167     /**
168      * Sets whether layer components can be split over multiple columns.
169      *
170      * \see splitLayer()
171      */
setSplitLayer(bool s)172     void setSplitLayer( bool s ) { mSplitLayer = s;}
173 
174     /**
175      * Returns TRUE if all columns should have equal widths.
176      *
177      * If FALSE is returned then columns will be individually resized to their minimum possible width.
178      *
179      * \see setEqualColumnWidth()
180      */
equalColumnWidth()181     bool equalColumnWidth() const { return mEqualColumnWidth; }
182 
183     /**
184      * Sets whether all columns should have equal widths.
185      *
186      * If FALSE, then then columns will be individually resized to their minimum possible width.
187      *
188      * \see equalColumnWidth()
189      */
setEqualColumnWidth(bool s)190     void setEqualColumnWidth( bool s ) { mEqualColumnWidth = s;}
191 
192     /**
193      * Returns the font color used for legend items.
194      *
195      * \see setFontColor()
196      */
fontColor()197     QColor fontColor() const {return mFontColor;}
198 
199     /**
200      * Sets the font color used for legend items.
201      *
202      * \see fontColor()
203      */
setFontColor(const QColor & c)204     void setFontColor( const QColor &c ) {mFontColor = c;}
205 
206     /**
207      * Returns layer font color, defaults to fontColor()
208      * \see setLayerFontColor()
209      * \see fontColor()
210      * \since QGIS 3.4.7
211      */
layerFontColor()212     QColor layerFontColor() const {return mLayerFontColor.isValid() ? mLayerFontColor : fontColor() ;}
213 
214     /**
215      * Sets layer font color to \a fontColor
216      * Overrides fontColor()
217      * \see layerFontColor()
218      * \see fontColor()
219      * \since QGIS 3.4.7
220      */
setLayerFontColor(const QColor & fontColor)221     void setLayerFontColor( const QColor &fontColor ) {mLayerFontColor = fontColor;}
222 
223     /**
224      * Returns the default symbol size (in millimeters) used for legend items.
225      *
226      * \see setSymbolSize()
227      */
symbolSize()228     QSizeF symbolSize() const {return mSymbolSize;}
229 
230     /**
231      * Sets the default symbol size (in millimeters) used for legend items.
232      *
233      * \see symbolSize()
234      */
setSymbolSize(QSizeF s)235     void setSymbolSize( QSizeF s ) {mSymbolSize = s;}
236 
237     /**
238      * Returns the maximum symbol size (in mm). 0.0 means there is no maximum set.
239      *
240      * \see setMaximumSymbolSize()
241      * \since QGIS 3.16
242      */
maximumSymbolSize()243     double maximumSymbolSize() const {return mMaxSymbolSize; }
244 
245     /**
246      * Set the maximum symbol \a size for symbol (in millimeters).
247      *
248      * A symbol size of 0.0 indicates no maximum is set.
249      *
250      * \see maximumSymbolSize()
251      * \since QGIS 3.16
252      */
setMaximumSymbolSize(double size)253     void setMaximumSymbolSize( double size ) { mMaxSymbolSize = size;}
254 
255     /**
256      * Returns the minimum symbol size (in mm). A value 0.0 means there is no minimum set.
257      *
258      * \see setMinimumSymbolSize
259      * \since QGIS 3.16
260      */
minimumSymbolSize()261     double minimumSymbolSize() const {return mMinSymbolSize; }
262 
263     /**
264      * Set the minimum symbol \a size for symbol (in millimeters).
265      *
266      * A symbol size of 0.0 indicates no minimum is set.
267      *
268      * \see minimumSymbolSize()
269      * \since QGIS 3.16
270      */
setMinimumSymbolSize(double size)271     void setMinimumSymbolSize( double size ) { mMinSymbolSize = size;}
272 
273     /**
274      * Sets the \a alignment for placement of legend symbols.
275      *
276      * Only Qt::AlignLeft or Qt::AlignRight are supported values.
277      *
278      * \see symbolAlignment()
279      * \since QGIS 3.10
280      */
setSymbolAlignment(Qt::AlignmentFlag alignment)281     void setSymbolAlignment( Qt::AlignmentFlag alignment ) { mSymbolAlignment = alignment; }
282 
283     /**
284      * Returns the alignment for placement of legend symbols.
285      *
286      * Only Qt::AlignLeft or Qt::AlignRight are supported values.
287      *
288      * \see setSymbolAlignment()
289      * \since QGIS 3.10
290      */
symbolAlignment()291     Qt::AlignmentFlag symbolAlignment() const { return mSymbolAlignment; }
292 
293     /**
294      * Returns whether a stroke will be drawn around raster symbol items.
295      * \see setDrawRasterStroke()
296      * \see rasterStrokeColor()
297      * \see rasterStrokeWidth()
298      * \since QGIS 2.12
299      */
drawRasterStroke()300     bool drawRasterStroke() const { return mRasterSymbolStroke; }
301 
302     /**
303      * Sets whether a stroke will be drawn around raster symbol items.
304      * \param enabled set to TRUE to draw borders
305      * \see drawRasterStroke()
306      * \see setRasterStrokeColor()
307      * \see setRasterStrokeWidth()
308      * \since QGIS 2.12
309      */
setDrawRasterStroke(bool enabled)310     void setDrawRasterStroke( bool enabled ) { mRasterSymbolStroke = enabled; }
311 
312     /**
313      * Returns the stroke color for the stroke drawn around raster symbol items. The stroke is
314      * only drawn if drawRasterStroke() is TRUE.
315      * \see setRasterStrokeColor()
316      * \see drawRasterStroke()
317      * \see rasterStrokeWidth()
318      * \since QGIS 2.12
319      */
rasterStrokeColor()320     QColor rasterStrokeColor() const { return mRasterStrokeColor; }
321 
322     /**
323      * Sets the stroke color for the stroke drawn around raster symbol items. The stroke is
324      * only drawn if drawRasterStroke() is TRUE.
325      * \param color stroke color
326      * \see rasterStrokeColor()
327      * \see setDrawRasterStroke()
328      * \see setRasterStrokeWidth()
329      * \since QGIS 2.12
330      */
setRasterStrokeColor(const QColor & color)331     void setRasterStrokeColor( const QColor &color ) { mRasterStrokeColor = color; }
332 
333     /**
334      * Returns the stroke width (in millimeters) for the stroke drawn around raster symbol items. The stroke is
335      * only drawn if drawRasterStroke() is TRUE.
336      * \see setRasterStrokeWidth()
337      * \see drawRasterStroke()
338      * \see rasterStrokeColor()
339      * \since QGIS 2.12
340      */
rasterStrokeWidth()341     double rasterStrokeWidth() const { return mRasterStrokeWidth; }
342 
343     /**
344      * Sets the stroke width for the stroke drawn around raster symbol items. The stroke is
345      * only drawn if drawRasterStroke() is TRUE.
346      * \param width stroke width in millimeters
347      * \see rasterStrokeWidth()
348      * \see setDrawRasterStroke()
349      * \see setRasterStrokeColor()
350      * \since QGIS 2.12
351      */
setRasterStrokeWidth(double width)352     void setRasterStrokeWidth( double width ) { mRasterStrokeWidth = width; }
353 
354     /**
355      * Returns the size (in millimeters) of WMS legend graphics shown in the legend.
356      *
357      * \see setWmsLegendSize()
358      */
wmsLegendSize()359     QSizeF wmsLegendSize() const {return mWmsLegendSize;}
360 
361     /**
362      * Sets the desired size (in millimeters) of WMS legend graphics shown in the legend.
363      *
364      * \see wmsLegendSize()
365      */
setWmsLegendSize(QSizeF s)366     void setWmsLegendSize( QSizeF s ) {mWmsLegendSize = s;}
367 
368     /**
369      * Returns the line spacing to use between lines of legend text.
370      *
371      * \see setLineSpacing()
372      */
lineSpacing()373     double lineSpacing() const { return mLineSpacing; }
374 
375     /**
376      * Sets the line spacing to use between lines of legend text.
377      *
378      * \see lineSpacing()
379      */
setLineSpacing(double s)380     void setLineSpacing( double s ) { mLineSpacing = s; }
381 
382     /**
383      * \deprecated Use scale factor from render contexts instead.
384      */
385     Q_DECL_DEPRECATED double mmPerMapUnit() const SIP_DEPRECATED;
386 
387     /**
388      * \deprecated Set scale factor on render contexts instead.
389      */
390     Q_DECL_DEPRECATED void setMmPerMapUnit( double mmPerMapUnit ) SIP_DEPRECATED;
391 
392     /**
393      * \deprecated Use flags from render contexts instead.
394      */
395     Q_DECL_DEPRECATED bool useAdvancedEffects() const SIP_DEPRECATED;
396 
397     /**
398      * \deprecated Set flag on render contexts instead.
399      */
400     Q_DECL_DEPRECATED void setUseAdvancedEffects( bool use ) SIP_DEPRECATED;
401 
402     /**
403      * Returns the legend map scale.
404      * The scale value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.
405      * \see setMapScale()
406      * \deprecated take this property from the render context instead
407      */
408     Q_DECL_DEPRECATED double mapScale() const SIP_DEPRECATED;
409 
410     /**
411      * Sets the legend map \a scale.
412      * The \a scale value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.
413      * \see mapScale()
414      * \deprecated set this property on the render context instead
415      */
416     Q_DECL_DEPRECATED void setMapScale( double scale ) SIP_DEPRECATED;
417 
418     /**
419      * Returns the factor of map units per pixel for symbols with size given in map units calculated by dpi and mmPerMapUnit
420      * \see setMapUnitsPerPixel()
421      * \deprecated take these properties on render contexts instead
422      */
423     Q_DECL_DEPRECATED double mapUnitsPerPixel() const SIP_DEPRECATED;
424 
425     /**
426      * Sets the mmPerMapUnit calculated by \a mapUnitsPerPixel mostly taken from the map settings.
427      * \see mapUnitsPerPixel()
428      * \deprecated set these properties on render contexts instead
429      */
430     Q_DECL_DEPRECATED void setMapUnitsPerPixel( double mapUnitsPerPixel ) SIP_DEPRECATED;
431 
432     /**
433      * \deprecated Take dpi from render contexts instead.
434      */
435     Q_DECL_DEPRECATED int dpi() const SIP_DEPRECATED;
436 
437     /**
438      * \deprecated Set dpi on render contexts instead.
439      */
440     Q_DECL_DEPRECATED void setDpi( int dpi ) SIP_DEPRECATED;
441 
442 // utility functions
443 
444     /**
445      * Splits a string using the wrap char taking into account handling empty
446      * wrap char which means no wrapping
447      */
448 
449     /**
450      * Returns the actual text to render for a legend item, split into separate lines.
451      *
452      * The expression \a context argument is used to correctly evaluated expressions contained
453      * within legend item text.
454      *
455      * \since QGIS 3.6
456      */
457     QStringList evaluateItemText( const QString &text, const QgsExpressionContext &context ) const;
458 
459     /**
460      * Splits a string using the wrap char taking into account handling empty
461      * wrap char which means no wrapping
462      */
463     QStringList splitStringForWrapping( const QString &stringToSplt ) const;
464 
465     /**
466      * Draws Text. Takes care about all the composer specific issues (calculation to
467      * pixel, scaling of font and painter to work around the Qt font bug)
468      */
469     void drawText( QPainter *p, double x, double y, const QString &text, const QFont &font ) const;
470 
471     /**
472      * Like the above, but with a rectangle for multiline text
473      * \param p painter to use
474      * \param rect rectangle to draw into
475      * \param text text to draw
476      * \param font font to use
477      * \param halignment optional horizontal alignment
478      * \param valignment optional vertical alignment
479      * \param flags allows for passing Qt::TextFlags to control appearance of rendered text
480      */
481     void drawText( QPainter *p, const QRectF &rect, const QString &text, const QFont &font, Qt::AlignmentFlag halignment = Qt::AlignLeft, Qt::AlignmentFlag valignment = Qt::AlignTop, int flags = Qt::TextWordWrap ) const;
482 
483     //! Returns a font where size is in pixel and font size is upscaled with FONT_WORKAROUND_SCALE
484     QFont scaledFontPixelSize( const QFont &font ) const;
485 
486     //! Calculates font to from point size to pixel size
487     double pixelFontSize( double pointSize ) const;
488 
489     //! Returns the font width in millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE
490     double textWidthMillimeters( const QFont &font, const QString &text ) const;
491 
492     //! Returns the font height of a character in millimeters
493     double fontHeightCharacterMM( const QFont &font, QChar c ) const;
494 
495     //! Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE
496     double fontAscentMillimeters( const QFont &font ) const;
497 
498     //! Returns the font descent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE
499     double fontDescentMillimeters( const QFont &font ) const;
500 
501   private:
502 
503     QString mTitle;
504 
505 //! Title alignment, one of Qt::AlignLeft, Qt::AlignHCenter, Qt::AlignRight)
506     Qt::AlignmentFlag mTitleAlignment = Qt::AlignLeft;
507 
508     QString mWrapChar;
509 
510     QColor mFontColor;
511 
512 //! Space between item box and contents
513     qreal mBoxSpace = 2;
514 
515 //! Width and height of symbol icon
516     QSizeF mSymbolSize;
517 
518 //! Maximum marker symbol size (in mm)
519     double mMaxSymbolSize = 0.0;
520 
521 //! Minimum marker symbol size (in mm)
522     double mMinSymbolSize = 0.0;
523 
524 //! Width and height of WMS legendGraphic pixmap
525     QSizeF mWmsLegendSize;
526 
527 //! Spacing between lines when wrapped
528     double mLineSpacing = 1;
529 
530 //! Space between columns
531     double mColumnSpace = 2;
532 
533 //! Number of legend columns
534     int mColumnCount = 1;
535 
536 //! Allow splitting layers into multiple columns
537     bool mSplitLayer = false;
538 
539 //! Use the same width (maximum) for all columns
540     bool mEqualColumnWidth = false;
541 
542     bool mRasterSymbolStroke = true;
543     QColor mRasterStrokeColor;
544     double mRasterStrokeWidth = 0.0;
545 
546     QMap<QgsLegendStyle::Style, QgsLegendStyle> mStyleMap;
547 
548 //! Conversion ratio between millimeters and map units - for symbols with size given in map units
549     double mMmPerMapUnit = 1;
550 
551 //! Whether to use advanced effects like opacity for symbols - may require their rasterization
552     bool mUseAdvancedEffects = true;
553 
554 //! Denominator of map's scale
555     double mMapScale = 1;
556 
557 //! DPI to be used when rendering legend
558     int mDpi = 96;
559 
560 //! Font color for layers, overrides font color
561     QColor mLayerFontColor;
562 
563 //! Symbol alignment
564     Qt::AlignmentFlag mSymbolAlignment = Qt::AlignLeft;
565 };
566 
567 
568 
569 #endif // QGSLEGENDSETTINGS_H
570