29#include <QFontMetricsF>
33using namespace Qt::StringLiterals;
42 QPainter *painter = context.
painter();
68 const QString unitLabel = settings.
unitLabel();
69 const bool hasUnitLabel = !unitLabel.isEmpty();
71 const bool hasUnitLabelAbove
78 double barTopPosition = scaledBoxContentSpace;
79 if ( hasUnitLabelAbove )
81 barTopPosition += fontMetrics.ascent() + scaledLabelBarSpace;
83 if ( hasDistanceLabelsAbove )
85 barTopPosition += fontMetrics.ascent() + scaledLabelBarSpace;
88 const double barBottomPosition = barTopPosition + scaledHeight;
89 const double barMiddleY = barTopPosition + scaledHeight / 2.0;
91 double distanceLabelY = 0.0;
92 if ( hasDistanceLabelsAbove )
94 distanceLabelY = barTopPosition - scaledLabelBarSpace;
96 else if ( hasDistanceLabelsBelow )
98 distanceLabelY = barBottomPosition + scaledLabelBarSpace + fontMetrics.ascent();
101 const QList<double> positions =
segmentPositions( context, scaleContext, settings );
109 for (
int i = 0; i < positions.size(); ++i )
111 const bool isFirstLabel = ( i == 0 );
112 const bool isLastLabel = ( i == positions.size() - 1 );
114 QString currentNumericLabel;
115 if ( i < nSegmentsLeft )
119 currentNumericLabel = firstLabel;
129 const double val = ( i - nSegmentsLeft + 1 ) * settings.
unitsPerSegment();
133 const double segmentWidthMM = ( i < nSegmentsLeft && nSegmentsLeft > 0 ) ? ( scaleContext.
segmentWidth / nSegmentsLeft ) : scaleContext.
segmentWidth;
137 QString labelText = currentNumericLabel;
143 labelText = unitLabel + labelText;
148 labelText = labelText + unitLabel;
160 double currentLabelNumber = 0.0;
161 int segmentCounter = 0;
162 QString currentNumericLabel;
164 for (
int i = 0; i < positions.size(); ++i )
166 if ( segmentCounter == 0 && nSegmentsLeft > 0 )
169 currentNumericLabel = firstLabel;
171 else if ( segmentCounter != 0 && segmentCounter == nSegmentsLeft )
174 currentLabelNumber = 0.0;
177 if ( segmentCounter >= nSegmentsLeft )
183 if ( segmentCounter == 0 || segmentCounter >= nSegmentsLeft )
185 const bool isFirstLabel = ( segmentCounter == 0 );
196 pos.setX( pos.x() + fontMetrics.horizontalAdvance( currentNumericLabel ) / 2.0 );
201 QString labelText = currentNumericLabel;
206 labelText = unitLabel + labelText;
210 labelText = labelText + unitLabel;
217 if ( segmentCounter >= nSegmentsLeft )
225 if ( !positions.isEmpty() )
228 QString lastLabelText = currentNumericLabel;
236 lastLabelText = unitLabel + lastLabelText;
240 lastLabelText = lastLabelText + unitLabel;
245 pos.setY( distanceLabelY );
255 - fontMetrics.horizontalAdvance( currentNumericLabel ) / 2.0
270 if ( hasUnitLabel && !positions.isEmpty() )
275 const double unitLabelYAbove = scaledBoxContentSpace + fontMetrics.ascent();
277 double unitLabelYBelow = barBottomPosition + scaledLabelBarSpace + fontMetrics.ascent();
278 if ( hasDistanceLabelsBelow )
280 unitLabelYBelow += fontMetrics.ascent() + scaledLabelBarSpace;
285 const QPointF pos( barLeftX - scaledLabelBarSpace, barMiddleY + ( fontMetrics.ascent() - fontMetrics.descent() ) / 2.0 );
290 const QPointF pos( barRightX + scaledLabelBarSpace, barMiddleY + ( fontMetrics.ascent() - fontMetrics.descent() ) / 2.0 );
295 const QPointF pos( barLeftX, unitLabelYAbove );
300 const QPointF pos( ( barLeftX + barRightX ) / 2.0, unitLabelYAbove );
305 const QPointF pos( barRightX, unitLabelYAbove );
310 const QPointF pos( barLeftX, unitLabelYBelow );
315 const QPointF pos( ( barLeftX + barRightX ) / 2.0, unitLabelYBelow );
320 const QPointF pos( barRightX, unitLabelYBelow );
326 const QPointF pos( firstDivCenterX, barMiddleY + ( fontMetrics.ascent() - fontMetrics.descent() ) / 2.0 );
352 firstLabelWidth = ( firstLabelWidth - scaleContext.
segmentWidth ) / 2.0;
356 firstLabelWidth = 0.0;
361 firstLabelWidth /= 2.0;
367 const QString largestLabel = largestNumberLabel + settings.
unitLabel();
368 double largestLabelWidth;
374 largestLabelWidth = ( largestLabelWidth - scaleContext.
segmentWidth ) / 2.0;
378 largestLabelWidth = 0.0;
390 const double width = firstLabelWidth + totalBarLength + 2.0 * settings.
pen().widthF() + largestLabelWidth + 2.0 * settings.
boxContentSpace();
395 return QSizeF( width, height );
402 const QString unitLabel = settings.
unitLabel();
403 const bool hasUnitLabel = !unitLabel.isEmpty();
411 double firstLabelWidth = 0.0;
414 const QString fullFirstLabel = unitLabel + firstNumLabel;
420 firstLabelWidth = ( fullWidth > firstSegmentWidth ) ? ( fullWidth - firstSegmentWidth ) / 2.0 : 0.0;
424 firstLabelWidth = fullWidth - numWidth / 2.0;
434 firstLabelWidth = ( fullWidth > firstSegmentWidth ) ? ( fullWidth - firstSegmentWidth ) / 2.0 : 0.0;
438 firstLabelWidth = fullWidth / 2.0;
445 QString largestLabel = largestNumberLabel;
450 largestLabel = unitLabel + largestLabel;
454 largestLabel = largestLabel + unitLabel;
458 double largestLabelWidth;
465 largestLabelWidth = ( largestLabelWidth - scaleContext.
segmentWidth ) / 2.0;
469 largestLabelWidth = 0.0;
495 double leftExtension = firstLabelWidth;
496 double rightExtension = largestLabelWidth;
505 leftExtension = std::max( leftExtension, unitLabelWidth + labelBarSpaceMM );
509 rightExtension = std::max( rightExtension, unitLabelWidth + labelBarSpaceMM );
513 leftExtension = std::max( leftExtension, unitLabelWidth / 2.0 );
517 rightExtension = std::max( rightExtension, unitLabelWidth / 2.0 );
521 const double centerOverhang = ( unitLabelWidth - totalBarLength ) / 2.0;
522 if ( centerOverhang > 0 )
524 leftExtension = std::max( leftExtension, centerOverhang );
525 rightExtension = std::max( rightExtension, centerOverhang );
530 const double width = leftExtension + totalBarLength + 2.0 * lineWidth + rightExtension + 2.0 * settings.
boxContentSpace();
538 barHeight = settings.
height();
549 bool hasUnitLabelAbove =
false;
550 bool hasUnitLabelBelow =
false;
561 double topSpace = 0.0;
562 if ( hasDistanceLabelsAbove )
566 if ( hasUnitLabelAbove )
572 double bottomSpace = 0.0;
573 if ( hasDistanceLabelsBelow )
577 if ( hasUnitLabelBelow )
583 height += topSpace + bottomSpace;
585 return QSizeF( width, height );
632 const QString unitLabel = settings.
unitLabel();
633 const bool hasUnitLabel = !unitLabel.isEmpty();
642 double firstLabelWidth = 0.0;
646 const QString fullFirstLabel = unitLabel + firstNumLabel;
652 if ( fullWidth > firstSegmentWidthPx )
654 firstLabelWidth = ( fullWidth - firstSegmentWidthPx ) / 2.0;
658 firstLabelWidth = 0.0;
663 firstLabelWidth = fullWidth - numWidth / 2.0;
673 if ( fullWidth > firstSegmentWidthPx )
675 firstLabelWidth = ( fullWidth - firstSegmentWidthPx ) / 2.0;
679 firstLabelWidth = 0.0;
684 firstLabelWidth = fullWidth / 2.0;
688 double xOffset = firstLabelWidth;
697 xOffset = std::max( xOffset, unitLabelWidth + scaledLabelBarSpace );
701 xOffset = std::max( xOffset, unitLabelWidth / 2.0 );
707 const double centerOverhang = ( unitLabelWidth - totalBarLengthPx ) / 2.0;
708 if ( centerOverhang > 0 )
710 xOffset = std::max( xOffset, centerOverhang );
720 QList<double> positions;
732 positions << currentXCoord;
733 currentXCoord += leftSegmentSize;
739 positions << currentXCoord;
747 QList<double> positions;
760 positions << currentXCoord;
761 currentXCoord += leftSegmentSize;
767 positions << currentXCoord;
775 QList<double> widths;
784 widths << leftSegmentSize;
804 const bool hasUnitLabelAbove
808 double barTopPosition = scaledBoxContentSpace;
809 if ( hasUnitLabelAbove )
811 barTopPosition += fontMetrics.ascent() + scaledLabelBarSpace;
815 barTopPosition += fontMetrics.ascent() + scaledLabelBarSpace;
818 return barTopPosition;
@ CenteredSegment
Labels are drawn centered relative to segment.
@ CenteredEdge
Labels are drawn centered relative to segment's edge.
@ AboveSegment
Labels are drawn above the scalebar.
@ BelowSegment
Labels are drawn below the scalebar.
@ AfterLastDistanceLabel
Placed after the last distance label.
@ CenteredBelow
Horizontally centered on the bar, below the bar.
@ LeftAbove
Text centered over the left edge of the bar, above the bar.
@ AfterBar
Vertically centered on the bar, after the bar ends.
@ BeforeBar
Vertically centered on the bar, before the bar begins.
@ BeforeEveryDistanceLabel
Placed before every distance label (as part of the distance label text).
@ CenteredAbove
Horizontally centered on the bar, above the bar.
@ RightBelow
Text centered over the right edge of the bar, below the bar.
@ OnBarAfterFirstDivision
Placed on top of the bar, after the first bar division.
@ BeforeFirstDistanceLabel
Placed before the first distance label.
@ RightAbove
Text centered over the right edge of the bar, above the bar.
@ AfterEveryDistanceLabel
Placed after every distance label (as part of the distance label text).
@ LeftBelow
Text centered over the left edge of the bar, below the bar.
QFlags< ScaleBarUnitLabelPlacement > ScaleBarUnitLabelPlacements
Available placement options for a scale bar's unit label.
@ Millimeters
Millimeters.
RAII class to pop scope from an expression context on destruction.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static double fontAscentMM(const QFont &font)
Calculates a font ascent in millimeters, including workarounds for QT font rendering issues.
static double textWidthMM(const QFont &font, const QString &text)
Calculate a font width in millimeters for a text string, including workarounds for QT font rendering ...
A context for numeric formats.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
double verticalOffset(QgsRenderContext &context, const QgsScaleBarSettings &settings) const
Calculates the vertical offset to the top of the bar, accounting for text placed above the bar.
virtual Flags flags() const
Returns the scalebar rendering flags, which dictates the renderer's behavior.
virtual bool applyDefaultSettings(QgsScaleBarSettings &settings) const
Applies any default settings relating to the scalebar to the passed settings object.
virtual int sortKey() const
Returns a sorting key value, where renderers with a lower sort key will be shown earlier in lists.
void drawDefaultLabels(QgsRenderContext &context, const QgsScaleBarSettings &settings, const QgsScaleBarRenderer::ScaleBarContext &scaleContext) const
Draws default scalebar labels using the specified settings and scaleContext to a destination render c...
virtual Q_DECL_DEPRECATED QSizeF calculateBoxSize(const QgsScaleBarSettings &settings, const QgsScaleBarRenderer::ScaleBarContext &scaleContext) const
Calculates the required box size (in millimeters) for a scalebar using the specified settings and sca...
QString firstLabelString(const QgsScaleBarSettings &settings) const
Returns the text used for the first label in the scalebar.
QList< double > segmentWidths(const QgsScaleBarRenderer::ScaleBarContext &scaleContext, const QgsScaleBarSettings &settings) const
Returns a list of widths of each segment of the scalebar.
Q_DECL_DEPRECATED QList< double > segmentPositions(const QgsScaleBarRenderer::ScaleBarContext &scaleContext, const QgsScaleBarSettings &settings) const
Returns a list of positions for each segment within the scalebar.
Q_DECL_DEPRECATED double firstLabelXOffset(const QgsScaleBarSettings &settings) const
Returns the x-offset (in millimeters) used for the first label in the scalebar.
@ FlagUsesSubdivisionsHeight
Renderer uses the scalebar subdivisions height (see QgsScaleBarSettings::subdivisionsHeight() ).
Stores the appearance and layout settings for scalebar drawing with QgsScaleBarRenderer.
double subdivisionsHeight() const
Returns the scalebar subdivisions height (in millimeters) for segments included in the right part of ...
QgsLineSymbol * lineSymbol() const
Returns the line symbol used to render the scalebar (only used for some scalebar types).
const QgsNumericFormat * numericFormat() const
Returns the numeric format used for numbers in the scalebar.
int numberOfSegments() const
Returns the number of segments included in the scalebar.
Qgis::ScaleBarUnitLabelPlacements unitLabelPlacements() const
Returns the placements for unit labels.
Qgis::ScaleBarDistanceLabelVerticalPlacement labelVerticalPlacement() const
Returns the vertical placement of text labels.
double unitsPerSegment() const
Returns the number of scalebar units per segment.
QgsTextFormat & textFormat()
Returns the text format used for drawing text in the scalebar.
Q_DECL_DEPRECATED QPen pen() const
Returns the pen used for drawing outlines in the scalebar.
double boxContentSpace() const
Returns the spacing (margin) between the scalebar box and content in millimeters.
QString unitLabel() const
Returns the label for units.
int numberOfSubdivisions() const
Returns the number of subdivisions for segments included in the right part of the scalebar (only used...
Qgis::ScaleBarDistanceLabelHorizontalPlacement labelHorizontalPlacement() const
Returns the horizontal placement of text labels.
Q_DECL_DEPRECATED QFont font() const
Returns the font used for drawing text in the scalebar.
double labelBarSpace() const
Returns the spacing (in millimeters) between labels and the scalebar.
double height() const
Returns the scalebar height (in millimeters).
int numberOfSegmentsLeft() const
Returns the number of segments included in the left part of the scalebar.
double mapUnitsPerScaleBarUnit() const
Returns the number of map units per scale bar unit used by the scalebar.
Scoped object for saving and restoring a QPainter object's state.
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
Container for all settings relating to text rendering.
QFont toQFont() const
Returns a QFont matching the relevant settings from this text format.
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
Draws text within a rectangle using the specified settings.
static QFontMetricsF fontMetrics(QgsRenderContext &context, const QgsTextFormat &format, double scaleFactor=1.0)
Returns the font metrics for the given text format, when rendered in the specified render context.
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
Single variable definition for use within a QgsExpressionContextScope.
Contains parameters regarding scalebar calculations.
bool isValid() const
Returns true if the context has valid settings.
QgsScaleBarRenderer::Flags flags
Scalebar renderer flags.
double segmentWidth
The width, in millimeters, of each individual segment drawn.