Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgshollowscalebarrenderer.cpp
3 : : --------------------------------
4 : : begin : March 2020
5 : : copyright : (C) 2020 by Nyall Dawson
6 : : email : nyall dot dawson at gmail dot com
7 : : ***************************************************************************/
8 : : /***************************************************************************
9 : : * *
10 : : * This program is free software; you can redistribute it and/or modify *
11 : : * it under the terms of the GNU General Public License as published by *
12 : : * the Free Software Foundation; either version 2 of the License, or *
13 : : * (at your option) any later version. *
14 : : * *
15 : : ***************************************************************************/
16 : :
17 : : #include "qgshollowscalebarrenderer.h"
18 : : #include "qgsscalebarsettings.h"
19 : : #include "qgslayoututils.h"
20 : : #include "qgssymbol.h"
21 : : #include "qgsfillsymbollayer.h"
22 : : #include "qgstextrenderer.h"
23 : : #include <QList>
24 : : #include <QPainter>
25 : :
26 : 5 : QString QgsHollowScaleBarRenderer::id() const
27 : : {
28 : 10 : return QStringLiteral( "hollow" );
29 : : }
30 : :
31 : 0 : QString QgsHollowScaleBarRenderer::visibleName() const
32 : : {
33 : 0 : return QObject::tr( "Hollow" );
34 : : }
35 : :
36 : 0 : QgsScaleBarRenderer::Flags QgsHollowScaleBarRenderer::flags() const
37 : : {
38 : 0 : return Flag::FlagUsesLineSymbol |
39 : 0 : Flag::FlagUsesFillSymbol |
40 : 0 : Flag::FlagUsesAlternateFillSymbol |
41 : 0 : Flag::FlagRespectsUnits |
42 : 0 : Flag::FlagRespectsMapUnitsPerScaleBarUnit |
43 : 0 : Flag::FlagUsesUnitLabel |
44 : 0 : Flag::FlagUsesSegments |
45 : 0 : Flag::FlagUsesLabelBarSpace |
46 : 0 : Flag::FlagUsesLabelVerticalPlacement |
47 : : Flag::FlagUsesLabelHorizontalPlacement;
48 : : }
49 : :
50 : 0 : int QgsHollowScaleBarRenderer::sortKey() const
51 : : {
52 : 0 : return 8;
53 : : }
54 : :
55 : 0 : QgsHollowScaleBarRenderer *QgsHollowScaleBarRenderer::clone() const
56 : : {
57 : 0 : return new QgsHollowScaleBarRenderer( *this );
58 : : }
59 : :
60 : 0 : void QgsHollowScaleBarRenderer::draw( QgsRenderContext &context, const QgsScaleBarSettings &settings, const ScaleBarContext &scaleContext ) const
61 : : {
62 : 0 : if ( !context.painter() )
63 : : {
64 : 0 : return;
65 : : }
66 : 0 : QPainter *painter = context.painter();
67 : :
68 : 0 : const double scaledLabelBarSpace = context.convertToPainterUnits( settings.labelBarSpace(), QgsUnitTypes::RenderMillimeters );
69 : 0 : const double scaledBoxContentSpace = context.convertToPainterUnits( settings.boxContentSpace(), QgsUnitTypes::RenderMillimeters );
70 : 0 : const QFontMetricsF fontMetrics = QgsTextRenderer::fontMetrics( context, settings.textFormat() );
71 : 0 : const double barTopPosition = scaledBoxContentSpace + ( settings.labelVerticalPlacement() == QgsScaleBarSettings::LabelAboveSegment ? fontMetrics.ascent() + scaledLabelBarSpace : 0 );
72 : 0 : const double barHeight = context.convertToPainterUnits( settings.height(), QgsUnitTypes::RenderMillimeters );
73 : :
74 : 0 : painter->save();
75 : 0 : context.setPainterFlagsUsingContext( painter );
76 : :
77 : 0 : std::unique_ptr< QgsLineSymbol > lineSymbol( settings.lineSymbol()->clone() );
78 : 0 : lineSymbol->startRender( context );
79 : :
80 : 0 : std::unique_ptr< QgsFillSymbol > fillSymbol1( settings.fillSymbol()->clone() );
81 : 0 : fillSymbol1->startRender( context );
82 : :
83 : 0 : std::unique_ptr< QgsFillSymbol > fillSymbol2( settings.alternateFillSymbol()->clone() );
84 : 0 : fillSymbol2->startRender( context );
85 : :
86 : 0 : painter->setPen( Qt::NoPen );
87 : 0 : painter->setBrush( Qt::NoBrush );
88 : :
89 : 0 : bool useColor = true; //alternate brush color/white
90 : 0 : const double xOffset = firstLabelXOffset( settings, context, scaleContext );
91 : :
92 : 0 : const QList<double> positions = segmentPositions( context, scaleContext, settings );
93 : 0 : const QList<double> widths = segmentWidths( scaleContext, settings );
94 : :
95 : : // draw the fill
96 : 0 : double minX = 0;
97 : 0 : double maxX = 0;
98 : 0 : QgsFillSymbol *currentSymbol = nullptr;
99 : 0 : for ( int i = 0; i < positions.size(); ++i )
100 : : {
101 : 0 : if ( useColor ) //alternating colors
102 : : {
103 : 0 : currentSymbol = fillSymbol1.get();
104 : 0 : }
105 : : else //secondary fill
106 : : {
107 : 0 : currentSymbol = fillSymbol2.get();
108 : : }
109 : :
110 : 0 : const double thisX = context.convertToPainterUnits( positions.at( i ), QgsUnitTypes::RenderMillimeters ) + xOffset;
111 : 0 : const double thisWidth = context.convertToPainterUnits( widths.at( i ), QgsUnitTypes::RenderMillimeters );
112 : :
113 : 0 : if ( i == 0 )
114 : 0 : minX = thisX;
115 : 0 : if ( i == positions.size() - 1 )
116 : 0 : maxX = thisX + thisWidth;
117 : :
118 : 0 : QRectF segmentRect( thisX, barTopPosition, thisWidth, barHeight );
119 : 0 : currentSymbol->renderPolygon( QPolygonF()
120 : 0 : << segmentRect.topLeft()
121 : 0 : << segmentRect.topRight()
122 : 0 : << segmentRect.bottomRight()
123 : 0 : << segmentRect.bottomLeft()
124 : 0 : << segmentRect.topLeft(), nullptr, nullptr, context );
125 : 0 : useColor = !useColor;
126 : 0 : }
127 : :
128 : : // and then the lines
129 : : // note that we do this layer-by-layer, to avoid ugliness where the lines touch the outer rect
130 : 0 : for ( int layer = 0; layer < lineSymbol->symbolLayerCount(); ++layer )
131 : : {
132 : : // horizontal lines
133 : 0 : bool drawLine = false;
134 : 0 : for ( int i = 0; i < positions.size(); ++i )
135 : : {
136 : 0 : drawLine = !drawLine;
137 : 0 : if ( !drawLine )
138 : 0 : continue;
139 : :
140 : 0 : const double lineX = context.convertToPainterUnits( positions.at( i ), QgsUnitTypes::RenderMillimeters ) + xOffset;
141 : 0 : const double lineLength = context.convertToPainterUnits( widths.at( i ), QgsUnitTypes::RenderMillimeters );
142 : 0 : lineSymbol->renderPolyline( QPolygonF()
143 : 0 : << QPointF( lineX, barTopPosition + barHeight / 2.0 )
144 : 0 : << QPointF( lineX + lineLength, barTopPosition + barHeight / 2.0 ),
145 : 0 : nullptr, context, layer );
146 : 0 : }
147 : :
148 : : // vertical lines
149 : 0 : for ( int i = 1; i < positions.size(); ++i )
150 : : {
151 : 0 : const double lineX = context.convertToPainterUnits( positions.at( i ), QgsUnitTypes::RenderMillimeters ) + xOffset;
152 : 0 : lineSymbol->renderPolyline( QPolygonF()
153 : 0 : << QPointF( lineX, barTopPosition )
154 : 0 : << QPointF( lineX, barTopPosition + barHeight ),
155 : 0 : nullptr, context, layer );
156 : 0 : }
157 : :
158 : : // outside line
159 : 0 : lineSymbol->renderPolyline( QPolygonF()
160 : 0 : << QPointF( minX, barTopPosition )
161 : 0 : << QPointF( maxX, barTopPosition )
162 : 0 : << QPointF( maxX, barTopPosition + barHeight )
163 : 0 : << QPointF( minX, barTopPosition + barHeight )
164 : 0 : << QPointF( minX, barTopPosition ),
165 : 0 : nullptr, context, layer );
166 : 0 : }
167 : :
168 : 0 : lineSymbol->stopRender( context );
169 : 0 : fillSymbol1->stopRender( context );
170 : 0 : fillSymbol2->stopRender( context );
171 : 0 : painter->restore();
172 : :
173 : : //draw labels using the default method
174 : 0 : drawDefaultLabels( context, settings, scaleContext );
175 : 0 : }
176 : :
177 : 0 : bool QgsHollowScaleBarRenderer::applyDefaultSettings( QgsScaleBarSettings &settings ) const
178 : : {
179 : : // null the fill symbols by default
180 : 0 : std::unique_ptr< QgsFillSymbol > fillSymbol = std::make_unique< QgsFillSymbol >();
181 : 0 : std::unique_ptr< QgsSimpleFillSymbolLayer > fillSymbolLayer = std::make_unique< QgsSimpleFillSymbolLayer >();
182 : 0 : fillSymbolLayer->setColor( QColor( 0, 0, 0 ) );
183 : 0 : fillSymbolLayer->setBrushStyle( Qt::NoBrush );
184 : 0 : fillSymbolLayer->setStrokeStyle( Qt::NoPen );
185 : 0 : fillSymbol->changeSymbolLayer( 0, fillSymbolLayer->clone() );
186 : 0 : settings.setFillSymbol( fillSymbol.release() );
187 : :
188 : 0 : fillSymbol = std::make_unique< QgsFillSymbol >();
189 : 0 : fillSymbolLayer->setColor( QColor( 255, 255, 255 ) );
190 : 0 : fillSymbol->changeSymbolLayer( 0, fillSymbolLayer.release() );
191 : 0 : settings.setAlternateFillSymbol( fillSymbol.release() );
192 : :
193 : : return true;
194 : 0 : }
195 : :
196 : :
197 : :
|