QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgslayoutitemscalebar.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitemscalebar.cpp
3  -------------------------
4  begin : November 2017
5  copyright : (C) 2017 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 "qgslayoutitemscalebar.h"
18 #include "qgslayoutitemregistry.h"
19 #include "qgslayoutitemmap.h"
20 #include "qgslayout.h"
21 #include "qgslayoututils.h"
22 #include "qgsdistancearea.h"
23 #include "qgsscalebarrenderer.h"
25 #include "qgsmapsettings.h"
29 #include "qgsrectangle.h"
30 #include "qgsproject.h"
31 #include "qgssymbollayerutils.h"
32 #include "qgsfontutils.h"
33 #include "qgsunittypes.h"
34 #include "qgssettings.h"
35 #include "qgsstyleentityvisitor.h"
36 
37 #include <QDomDocument>
38 #include <QDomElement>
39 #include <QFontMetricsF>
40 #include <QPainter>
41 
42 #include <cmath>
43 
45  : QgsLayoutItem( layout )
46 {
49 }
50 
52 {
54 }
55 
57 {
58  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemScaleBar.svg" ) );
59 }
60 
62 {
63  return new QgsLayoutItemScaleBar( layout );
64 }
65 
67 {
68  return QgsLayoutSize( mStyle->calculateBoxSize( mSettings, createScaleContext() ), QgsUnitTypes::LayoutMillimeters );
69 }
70 
72 {
73  if ( !mStyle )
74  return;
75 
76  mStyle->draw( context.renderContext(), mSettings, createScaleContext() );
77 }
78 
80 {
81  if ( !mStyle )
82  {
83  mSettings.setNumberOfSegments( nSegments );
84  return;
85  }
86  mSettings.setNumberOfSegments( nSegments );
88 }
89 
91 {
92  if ( !mStyle )
93  {
94  mSettings.setUnitsPerSegment( units );
95  return;
96  }
97  mSettings.setUnitsPerSegment( units );
98  refreshSegmentMillimeters();
100 }
101 
103 {
104  if ( !mStyle )
105  {
106  mSettings.setSegmentSizeMode( mode );
107  return;
108  }
109  mSettings.setSegmentSizeMode( mode );
110  refreshSegmentMillimeters();
112 }
113 
115 {
116  if ( !mStyle )
117  {
118  mSettings.setMinimumBarWidth( minWidth );
119  return;
120  }
121  mSettings.setMinimumBarWidth( minWidth );
122  refreshSegmentMillimeters();
124 }
125 
127 {
128  if ( !mStyle )
129  {
130  mSettings.setMaximumBarWidth( maxWidth );
131  return;
132  }
133  mSettings.setMaximumBarWidth( maxWidth );
134  refreshSegmentMillimeters();
136 }
137 
139 {
140  return mSettings.textFormat();
141 }
142 
144 {
145  mSettings.setTextFormat( format );
146  refreshItemSize();
147  emit changed();
148 }
149 
151 {
152  if ( !mStyle )
153  {
154  mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
155  return;
156  }
157  mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
159 }
160 
162 {
163  if ( !mStyle )
164  {
165  mSettings.setBoxContentSpace( space );
166  return;
167  }
168  mSettings.setBoxContentSpace( space );
169  refreshItemSize();
170 }
171 
173 {
174  disconnectCurrentMap();
175 
176  mMap = map;
177 
178  if ( !map )
179  {
180  return;
181  }
182 
183  connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
184  connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
185 
186  refreshSegmentMillimeters();
187  emit changed();
188 }
189 
190 void QgsLayoutItemScaleBar::disconnectCurrentMap()
191 {
192  if ( !mMap )
193  {
194  return;
195  }
196 
197  disconnect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
198  disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
199  mMap = nullptr;
200 }
201 
203 {
205 
206  bool forceUpdate = false;
207  //updates data defined properties and redraws item to match
209  {
210  QBrush b = mSettings.brush();
212  mSettings.setBrush( b );
213  forceUpdate = true;
214  }
216  {
217  QBrush b = mSettings.brush2();
219  mSettings.setBrush2( b );
220  forceUpdate = true;
221  }
223  {
224  QPen p = mSettings.pen();
226  mSettings.setPen( p );
227  forceUpdate = true;
228  }
230  {
231  QPen p = mSettings.pen();
233  mSettings.setPen( p );
234  forceUpdate = true;
235  }
236  if ( forceUpdate )
237  {
238  refreshItemSize();
239  update();
240  }
241 
243 }
244 
245 void QgsLayoutItemScaleBar::refreshSegmentMillimeters()
246 {
247  if ( mMap )
248  {
249  //get mm dimension of composer map
250  QRectF composerItemRect = mMap->rect();
251 
252  switch ( mSettings.segmentSizeMode() )
253  {
255  {
256  //calculate size depending on mNumUnitsPerSegment
257  mSegmentMillimeters = composerItemRect.width() / mapWidth() * mSettings.unitsPerSegment();
258  break;
259  }
260 
262  {
263  if ( mSettings.maximumBarWidth() < mSettings.minimumBarWidth() )
264  {
265  mSegmentMillimeters = 0;
266  }
267  else
268  {
269  double nSegments = ( mSettings.numberOfSegmentsLeft() != 0 ) + mSettings.numberOfSegments();
270  // unitsPerSegments which fit minBarWidth resp. maxBarWidth
271  double minUnitsPerSeg = ( mSettings.minimumBarWidth() * mapWidth() ) / ( nSegments * composerItemRect.width() );
272  double maxUnitsPerSeg = ( mSettings.maximumBarWidth() * mapWidth() ) / ( nSegments * composerItemRect.width() );
273  mSettings.setUnitsPerSegment( QgsLayoutUtils::calculatePrettySize( minUnitsPerSeg, maxUnitsPerSeg ) );
274  mSegmentMillimeters = composerItemRect.width() / mapWidth() * mSettings.unitsPerSegment();
275  }
276  break;
277  }
278  }
279  }
280 }
281 
282 double QgsLayoutItemScaleBar::mapWidth() const
283 {
284  if ( !mMap )
285  {
286  return 0.0;
287  }
288 
289  QgsRectangle mapExtent = mMap->extent();
290  if ( mSettings.units() == QgsUnitTypes::DistanceUnknownUnit )
291  {
292  return mapExtent.width();
293  }
294  else
295  {
296  QgsDistanceArea da;
297  da.setSourceCrs( mMap->crs(), mLayout->project()->transformContext() );
298  da.setEllipsoid( mLayout->project()->ellipsoid() );
299 
301  double measure = da.measureLine( QgsPointXY( mapExtent.xMinimum(), mapExtent.yMinimum() ),
302  QgsPointXY( mapExtent.xMaximum(), mapExtent.yMinimum() ) );
303  measure /= QgsUnitTypes::fromUnitToUnitFactor( mSettings.units(), units );
304  return measure;
305  }
306 }
307 
308 QgsScaleBarRenderer::ScaleBarContext QgsLayoutItemScaleBar::createScaleContext() const
309 {
311  scaleContext.size = rect().size();
312  scaleContext.segmentWidth = mSegmentMillimeters;
313  scaleContext.scale = mMap ? mMap->scale() : 1.0;
314  return scaleContext;
315 }
316 
318 {
319  mSettings.setLabelVerticalPlacement( placement );
320  refreshItemSize();
321  emit changed();
322 }
323 
325 {
326  mSettings.setLabelHorizontalPlacement( placement );
327  refreshItemSize();
328  emit changed();
329 }
330 
332 {
333  mSettings.setAlignment( a );
334  refreshItemSize();
335  emit changed();
336 }
337 
339 {
340  mSettings.setUnits( u );
341  refreshSegmentMillimeters();
342  refreshItemSize();
343  emit changed();
344 }
345 
347 {
348  if ( mSettings.lineJoinStyle() == style )
349  {
350  //no change
351  return;
352  }
353  mSettings.setLineJoinStyle( style );
354  update();
355  emit changed();
356 }
357 
359 {
360  if ( mSettings.lineCapStyle() == style )
361  {
362  //no change
363  return;
364  }
365  mSettings.setLineCapStyle( style );
366  update();
367  emit changed();
368 }
369 
371 {
372  //style
373  mStyle = qgis::make_unique< QgsSingleBoxScaleBarRenderer >();
374 
375  //default to no background
376  setBackgroundEnabled( false );
377 
378  //get default composer font from settings
379  QgsSettings settings;
380  QString defaultFontString = settings.value( QStringLiteral( "LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
381  QgsTextFormat format;
382  QFont f;
383  if ( !defaultFontString.isEmpty() )
384  {
385  f.setFamily( defaultFontString );
386  }
387  format.setFont( f );
388  format.setSize( 12.0 );
390 
391  mSettings.setTextFormat( format );
392 
394  refreshItemSize();
395 
396  emit changed();
397 }
398 
400 {
401  if ( !mMap )
403 
405  // start with crs units
408  {
409  // geographic CRS, use metric units
411  }
412 
413  // try to pick reasonable choice between metric / imperial units
414  double widthInSelectedUnits = mapWidth();
415  double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
416  switch ( unit )
417  {
419  {
420  if ( initialUnitsPerSegment > 1000.0 )
421  {
423  }
424  break;
425  }
427  {
428  if ( initialUnitsPerSegment > 5419.95 )
429  {
431  }
432  break;
433  }
434  default:
435  break;
436  }
437 
438  return unit;
439 }
440 
442 {
443  mSettings.setUnits( units );
444  if ( mMap )
445  {
446  double upperMagnitudeMultiplier = 1.0;
447  double widthInSelectedUnits = mapWidth();
448  double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
449  mSettings.setUnitsPerSegment( initialUnitsPerSegment );
450 
452  upperMagnitudeMultiplier = 1;
453 
454  double segmentWidth = initialUnitsPerSegment / upperMagnitudeMultiplier;
455  int segmentMagnitude = std::floor( std::log10( segmentWidth ) );
456  double unitsPerSegment = upperMagnitudeMultiplier * ( std::pow( 10.0, segmentMagnitude ) );
457  double multiplier = std::floor( ( widthInSelectedUnits / ( unitsPerSegment * 10.0 ) ) / 2.5 ) * 2.5;
458 
459  if ( multiplier > 0 )
460  {
461  unitsPerSegment = unitsPerSegment * multiplier;
462  }
463  mSettings.setUnitsPerSegment( unitsPerSegment );
464  mSettings.setMapUnitsPerScaleBarUnit( upperMagnitudeMultiplier );
465 
466  mSettings.setNumberOfSegments( 2 );
467  mSettings.setNumberOfSegmentsLeft( 0 );
468  }
469 
470  refreshSegmentMillimeters();
472  emit changed();
473 }
474 
476 {
477  if ( !mStyle )
478  return;
479 
480  double widthMM = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
481  QgsLayoutSize currentSize = sizeWithUnits();
482  currentSize.setWidth( mLayout->renderContext().measurementConverter().convert( QgsLayoutMeasurement( widthMM, QgsUnitTypes::LayoutMillimeters ), currentSize.units() ).length() );
483  attemptResize( currentSize );
484  update();
485  emit changed();
486 }
487 
489 {
490  //Don't adjust box size for numeric scale bars:
491  if ( mStyle && mStyle->name() != QLatin1String( "Numeric" ) )
492  {
493  refreshItemSize();
494  }
495  QgsLayoutItem::update();
496 }
497 
498 void QgsLayoutItemScaleBar::updateScale()
499 {
500  refreshSegmentMillimeters();
502  update();
503 }
504 
505 void QgsLayoutItemScaleBar::setStyle( const QString &styleName )
506 {
507  //switch depending on style name
508  if ( styleName == QLatin1String( "Single Box" ) )
509  {
510  mStyle = qgis::make_unique< QgsSingleBoxScaleBarRenderer >();
511  }
512  else if ( styleName == QLatin1String( "Double Box" ) )
513  {
514  mStyle = qgis::make_unique< QgsDoubleBoxScaleBarRenderer >();
515  }
516  else if ( styleName == QLatin1String( "Line Ticks Middle" ) || styleName == QLatin1String( "Line Ticks Down" ) || styleName == QLatin1String( "Line Ticks Up" ) )
517  {
518  std::unique_ptr< QgsTicksScaleBarRenderer > tickStyle = qgis::make_unique< QgsTicksScaleBarRenderer >();
519  if ( styleName == QLatin1String( "Line Ticks Middle" ) )
520  {
521  tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksMiddle );
522  }
523  else if ( styleName == QLatin1String( "Line Ticks Down" ) )
524  {
525  tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksDown );
526  }
527  else if ( styleName == QLatin1String( "Line Ticks Up" ) )
528  {
529  tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksUp );
530  }
531  mStyle = std::move( tickStyle );
532  }
533  else if ( styleName == QLatin1String( "Numeric" ) )
534  {
535  mStyle = qgis::make_unique< QgsNumericScaleBarRenderer >();
536  }
537  refreshItemSize();
538  emit changed();
539 }
540 
542 {
543  if ( mStyle )
544  {
545  return mStyle->name();
546  }
547  else
548  {
549  return QString();
550  }
551 }
552 
554 {
555  return mSettings.textFormat().font();
556 }
557 
559 {
561  mSettings.setFont( font );
563  refreshItemSize();
564  emit changed();
565 }
566 
568 {
569  QColor color = mSettings.textFormat().color();
570  color.setAlphaF( mSettings.textFormat().opacity() );
571  return color;
572 }
573 
574 void QgsLayoutItemScaleBar::setFontColor( const QColor &color )
575 {
576  mSettings.textFormat().setColor( color );
577  mSettings.textFormat().setOpacity( color.alphaF() );
578 }
579 
580 bool QgsLayoutItemScaleBar::writePropertiesToElement( QDomElement &composerScaleBarElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
581 {
582  composerScaleBarElem.setAttribute( QStringLiteral( "height" ), QString::number( mSettings.height() ) );
583  composerScaleBarElem.setAttribute( QStringLiteral( "labelBarSpace" ), QString::number( mSettings.labelBarSpace() ) );
584  composerScaleBarElem.setAttribute( QStringLiteral( "boxContentSpace" ), QString::number( mSettings.boxContentSpace() ) );
585  composerScaleBarElem.setAttribute( QStringLiteral( "numSegments" ), mSettings.numberOfSegments() );
586  composerScaleBarElem.setAttribute( QStringLiteral( "numSegmentsLeft" ), mSettings.numberOfSegmentsLeft() );
587  composerScaleBarElem.setAttribute( QStringLiteral( "numUnitsPerSegment" ), QString::number( mSettings.unitsPerSegment() ) );
588  composerScaleBarElem.setAttribute( QStringLiteral( "segmentSizeMode" ), mSettings.segmentSizeMode() );
589  composerScaleBarElem.setAttribute( QStringLiteral( "minBarWidth" ), mSettings.minimumBarWidth() );
590  composerScaleBarElem.setAttribute( QStringLiteral( "maxBarWidth" ), mSettings.maximumBarWidth() );
591  composerScaleBarElem.setAttribute( QStringLiteral( "segmentMillimeters" ), QString::number( mSegmentMillimeters ) );
592  composerScaleBarElem.setAttribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QString::number( mSettings.mapUnitsPerScaleBarUnit() ) );
593 
594  QDomElement textElem = mSettings.textFormat().writeXml( doc, rwContext );
595  composerScaleBarElem.appendChild( textElem );
596 
597  composerScaleBarElem.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mSettings.lineWidth() ) );
598  composerScaleBarElem.setAttribute( QStringLiteral( "unitLabel" ), mSettings.unitLabel() );
599  composerScaleBarElem.setAttribute( QStringLiteral( "unitType" ), QgsUnitTypes::encodeUnit( mSettings.units() ) );
600  composerScaleBarElem.setAttribute( QStringLiteral( "lineJoinStyle" ), QgsSymbolLayerUtils::encodePenJoinStyle( mSettings.lineJoinStyle() ) );
601  composerScaleBarElem.setAttribute( QStringLiteral( "lineCapStyle" ), QgsSymbolLayerUtils::encodePenCapStyle( mSettings.lineCapStyle() ) );
602 
603  //style
604  if ( mStyle )
605  {
606  composerScaleBarElem.setAttribute( QStringLiteral( "style" ), mStyle->name() );
607  }
608 
609  //map id
610  if ( mMap )
611  {
612  composerScaleBarElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
613  }
614 
615  //colors
616 
617  //fill color
618  QDomElement fillColorElem = doc.createElement( QStringLiteral( "fillColor" ) );
619  fillColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor().red() ) );
620  fillColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor().green() ) );
621  fillColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor().blue() ) );
622  fillColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor().alpha() ) );
623  composerScaleBarElem.appendChild( fillColorElem );
624 
625  //fill color 2
626  QDomElement fillColor2Elem = doc.createElement( QStringLiteral( "fillColor2" ) );
627  fillColor2Elem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor2().red() ) );
628  fillColor2Elem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor2().green() ) );
629  fillColor2Elem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor2().blue() ) );
630  fillColor2Elem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor2().alpha() ) );
631  composerScaleBarElem.appendChild( fillColor2Elem );
632 
633  //pen color
634  QDomElement strokeColorElem = doc.createElement( QStringLiteral( "strokeColor" ) );
635  strokeColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.lineColor().red() ) );
636  strokeColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.lineColor().green() ) );
637  strokeColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.lineColor().blue() ) );
638  strokeColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.lineColor().alpha() ) );
639  composerScaleBarElem.appendChild( strokeColorElem );
640 
641  //label vertical/horizontal placement
642  composerScaleBarElem.setAttribute( QStringLiteral( "labelVerticalPlacement" ), QString::number( static_cast< int >( mSettings.labelVerticalPlacement() ) ) );
643  composerScaleBarElem.setAttribute( QStringLiteral( "labelHorizontalPlacement" ), QString::number( static_cast< int >( mSettings.labelHorizontalPlacement() ) ) );
644 
645  //alignment
646  composerScaleBarElem.setAttribute( QStringLiteral( "alignment" ), QString::number( static_cast< int >( mSettings.alignment() ) ) );
647 
648  return true;
649 }
650 
651 bool QgsLayoutItemScaleBar::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
652 {
653  mSettings.setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
654  mSettings.setLabelBarSpace( itemElem.attribute( QStringLiteral( "labelBarSpace" ), QStringLiteral( "3.0" ) ).toDouble() );
655  mSettings.setBoxContentSpace( itemElem.attribute( QStringLiteral( "boxContentSpace" ), QStringLiteral( "1.0" ) ).toDouble() );
656  mSettings.setNumberOfSegments( itemElem.attribute( QStringLiteral( "numSegments" ), QStringLiteral( "2" ) ).toInt() );
657  mSettings.setNumberOfSegmentsLeft( itemElem.attribute( QStringLiteral( "numSegmentsLeft" ), QStringLiteral( "0" ) ).toInt() );
658  mSettings.setUnitsPerSegment( itemElem.attribute( QStringLiteral( "numUnitsPerSegment" ), QStringLiteral( "1.0" ) ).toDouble() );
659  mSettings.setSegmentSizeMode( static_cast<QgsScaleBarSettings::SegmentSizeMode>( itemElem.attribute( QStringLiteral( "segmentSizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
660  mSettings.setMinimumBarWidth( itemElem.attribute( QStringLiteral( "minBarWidth" ), QStringLiteral( "50" ) ).toDouble() );
661  mSettings.setMaximumBarWidth( itemElem.attribute( QStringLiteral( "maxBarWidth" ), QStringLiteral( "150" ) ).toDouble() );
662  mSegmentMillimeters = itemElem.attribute( QStringLiteral( "segmentMillimeters" ), QStringLiteral( "0.0" ) ).toDouble();
663  mSettings.setMapUnitsPerScaleBarUnit( itemElem.attribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QStringLiteral( "1.0" ) ).toDouble() );
664  mSettings.setLineWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "0.3" ) ).toDouble() );
665  mSettings.setUnitLabel( itemElem.attribute( QStringLiteral( "unitLabel" ) ) );
666  mSettings.setLineJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "lineJoinStyle" ), QStringLiteral( "miter" ) ) ) );
667  mSettings.setLineCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( itemElem.attribute( QStringLiteral( "lineCapStyle" ), QStringLiteral( "square" ) ) ) );
668 
669  QDomNodeList textFormatNodeList = itemElem.elementsByTagName( QStringLiteral( "text-style" ) );
670  if ( !textFormatNodeList.isEmpty() )
671  {
672  QDomElement textFormatElem = textFormatNodeList.at( 0 ).toElement();
673  mSettings.textFormat().readXml( textFormatElem, context );
674  }
675  else
676  {
677  QFont f;
678  if ( !QgsFontUtils::setFromXmlChildNode( f, itemElem, QStringLiteral( "scaleBarFont" ) ) )
679  {
680  f.fromString( itemElem.attribute( QStringLiteral( "font" ), QString() ) );
681  }
682  mSettings.textFormat().setFont( f );
683  if ( f.pointSizeF() > 0 )
684  {
685  mSettings.textFormat().setSize( f.pointSizeF() );
687  }
688  else if ( f.pixelSize() > 0 )
689  {
690  mSettings.textFormat().setSize( f.pixelSize() );
692  }
693  }
694 
695  //colors
696  //fill color
697  QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "fillColor" ) );
698  if ( !fillColorList.isEmpty() )
699  {
700  QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
701  bool redOk, greenOk, blueOk, alphaOk;
702  int fillRed, fillGreen, fillBlue, fillAlpha;
703 
704  fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
705  fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
706  fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
707  fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
708 
709  if ( redOk && greenOk && blueOk && alphaOk )
710  {
711  mSettings.setFillColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
712  }
713  }
714  else
715  {
716  mSettings.setFillColor( QColor( itemElem.attribute( QStringLiteral( "brushColor" ), QStringLiteral( "#000000" ) ) ) );
717  }
718 
719  //fill color 2
720  QDomNodeList fillColor2List = itemElem.elementsByTagName( QStringLiteral( "fillColor2" ) );
721  if ( !fillColor2List.isEmpty() )
722  {
723  QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
724  bool redOk, greenOk, blueOk, alphaOk;
725  int fillRed, fillGreen, fillBlue, fillAlpha;
726 
727  fillRed = fillColor2Elem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
728  fillGreen = fillColor2Elem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
729  fillBlue = fillColor2Elem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
730  fillAlpha = fillColor2Elem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
731 
732  if ( redOk && greenOk && blueOk && alphaOk )
733  {
734  mSettings.setFillColor2( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
735  }
736  }
737  else
738  {
739  mSettings.setFillColor2( QColor( itemElem.attribute( QStringLiteral( "brush2Color" ), QStringLiteral( "#ffffff" ) ) ) );
740  }
741 
742  //stroke color
743  QDomNodeList strokeColorList = itemElem.elementsByTagName( QStringLiteral( "strokeColor" ) );
744  if ( !strokeColorList.isEmpty() )
745  {
746  QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
747  bool redOk, greenOk, blueOk, alphaOk;
748  int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
749 
750  strokeRed = strokeColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
751  strokeGreen = strokeColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
752  strokeBlue = strokeColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
753  strokeAlpha = strokeColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
754 
755  if ( redOk && greenOk && blueOk && alphaOk )
756  {
757  mSettings.setLineColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
758  QPen p = mSettings.pen();
759  p.setColor( mSettings.lineColor() );
760  mSettings.setPen( p );
761  }
762  }
763  else
764  {
765  mSettings.setLineColor( QColor( itemElem.attribute( QStringLiteral( "penColor" ), QStringLiteral( "#000000" ) ) ) );
766  QPen p = mSettings.pen();
767  p.setColor( mSettings.lineColor() );
768  mSettings.setPen( p );
769  }
770 
771  //font color
772  QDomNodeList textColorList = itemElem.elementsByTagName( QStringLiteral( "textColor" ) );
773  if ( !textColorList.isEmpty() )
774  {
775  QDomElement textColorElem = textColorList.at( 0 ).toElement();
776  bool redOk, greenOk, blueOk, alphaOk;
777  int textRed, textGreen, textBlue, textAlpha;
778 
779  textRed = textColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
780  textGreen = textColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
781  textBlue = textColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
782  textAlpha = textColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
783 
784  if ( redOk && greenOk && blueOk && alphaOk )
785  {
786  mSettings.textFormat().setColor( QColor( textRed, textGreen, textBlue, textAlpha ) );
787  }
788  }
789  else if ( itemElem.hasAttribute( QStringLiteral( "fontColor" ) ) )
790  {
791  QColor c;
792  c.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
793  mSettings.textFormat().setColor( c );
794  }
795 
796  //style
797  QString styleString = itemElem.attribute( QStringLiteral( "style" ), QString() );
798  setStyle( styleString.toLocal8Bit().data() );
799 
800  if ( itemElem.attribute( QStringLiteral( "unitType" ) ).isEmpty() )
801  {
803  switch ( itemElem.attribute( QStringLiteral( "units" ) ).toInt() )
804  {
805  case 0:
807  break;
808  case 1:
810  break;
811  case 2:
813  break;
814  case 3:
816  break;
817  }
818  mSettings.setUnits( u );
819  }
820  else
821  {
822  mSettings.setUnits( QgsUnitTypes::decodeDistanceUnit( itemElem.attribute( QStringLiteral( "unitType" ) ) ) );
823  }
824 
825  mSettings.setLabelVerticalPlacement( static_cast< QgsScaleBarSettings::LabelVerticalPlacement >( itemElem.attribute( QStringLiteral( "labelVerticalPlacement" ), QStringLiteral( "0" ) ).toInt() ) );
826  mSettings.setLabelHorizontalPlacement( static_cast< QgsScaleBarSettings::LabelHorizontalPlacement >( itemElem.attribute( QStringLiteral( "labelHorizontalPlacement" ), QStringLiteral( "0" ) ).toInt() ) );
827 
828  mSettings.setAlignment( static_cast< QgsScaleBarSettings::Alignment >( itemElem.attribute( QStringLiteral( "alignment" ), QStringLiteral( "0" ) ).toInt() ) );
829 
830  //map
831  disconnectCurrentMap();
832  mMap = nullptr;
833  mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
834  return true;
835 }
836 
837 
839 {
840  if ( mLayout && !mMapUuid.isEmpty() )
841  {
842  disconnectCurrentMap();
843  mMap = qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mMapUuid, true ) );
844  if ( mMap )
845  {
846  connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
847  connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
848  }
849  }
850 
851  updateScale();
852 }
853 
855 {
856  QgsStyleTextFormatEntity entity( mSettings.textFormat() );
857  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
858  return false;
859 
860  return true;
861 }
862 
864 {
866 }
QgsUnitTypes::DistanceUnit guessUnits() const
Attempts to guess the most reasonable unit choice for the scalebar, given the current linked map&#39;s sc...
QgsUnitTypes::DistanceUnit lengthUnits() const
Returns the units of distance for length calculations made by this object.
The class is used as a container of context for various read/write operations on other objects...
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color...
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void setMinimumBarWidth(double width)
Sets the minimum width (in millimeters) for scale bar segments.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
double mapUnitsPerScaleBarUnit() const
Returns the number of map units per scale bar unit used by the scalebar.
Scale bar segment size is calculated to fit a size range.
QBrush brush() const
Returns the primary brush used for filling the scalebar.
QString style() const
Returns the scale bar style name.
void setOpacity(double opacity)
Sets the text&#39;s opacity.
void setLineColor(const QColor &color)
Sets the color used for lines in the scalebar.
void setLineJoinStyle(Qt::PenJoinStyle style)
Sets the join style used when drawing the lines in the scalebar.
double opacity() const
Returns the text&#39;s opacity.
Base class for graphical items within a QgsLayout.
QgsLayoutSize minimumSize() const override
Returns the minimum allowed size of the item, if applicable, or an empty size if item can be freely r...
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
QString unitLabel() const
Returns the label for units.
Q_DECL_DEPRECATED QFont font() const
Returns the font used for drawing text in the scalebar.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double...
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
Refreshes a data defined property for the item by reevaluating the property&#39;s value and redrawing the...
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QPen pen() const
Returns the pen used for drawing outlines in the scalebar.
LabelVerticalPlacement
Label vertical placement.
double segmentWidth
The width, in millimeters, of each individual segment drawn.
Alignment alignment() const
Returns the scalebar alignment.
void setPen(const QPen &pen)
Sets the pen used for drawing outlines in the scalebar.
Q_DECL_DEPRECATED void setFontColor(const QColor &color)
Sets the color used for drawing text in the scalebar.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QColor fillColor2() const
Returns the secondary color used for fills in the scalebar.
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map item linked to the scalebar.
A class to represent a 2D point.
Definition: qgspointxy.h:43
void extentChanged()
Emitted when the map&#39;s extent changes.
SegmentSizeMode segmentSizeMode() const
Returns the size mode for the scale bar segments.
void setBoxContentSpace(double space)
Sets the space (margin) between the scalebar box and content in millimeters.
QgsLayoutSize sizeWithUnits() const
Returns the item&#39;s current size, including units.
void setLineCapStyle(Qt::PenCapStyle style)
Sets the cap style used when drawing the lines in the scalebar.
void setLabelVerticalPlacement(LabelVerticalPlacement placement)
Sets the vertical placement of text labels.
void setFont(const QFont &font)
Sets the font used for rendering text.
double lineWidth() const
Returns the line width in millimeters for lines in the scalebar.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:649
static double calculatePrettySize(double minimumSize, double maximumSize)
Calculates a "pretty" size which falls between the range [minimumSize, maximumSize].
QColor color() const
Returns the color that text will be rendered in.
Alignment
Scalebar alignment.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void update()
Adjusts the scale bar box size and updates the item.
void setAlignment(QgsScaleBarSettings::Alignment alignment)
Sets the scalebar alignment.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
QColor lineColor() const
Returns the color used for lines in the scalebar.
Item can only be placed on layers with other items of the same type, but multiple items of this type ...
static Q_INVOKABLE QgsUnitTypes::DistanceUnit decodeDistanceUnit(const QString &string, bool *ok=nullptr)
Decodes a distance unit from a string.
const QgsCoordinateReferenceSystem & crs
An interface for classes which can visit style entity (e.g.
void setSegmentSizeMode(QgsScaleBarSettings::SegmentSizeMode mode)
Sets the size mode for scale bar segments.
void setStyle(const QString &name)
Sets the scale bar style by name.
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties)
Refreshes a data defined property for the item by reevaluating the property&#39;s value and redrawing the...
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
LabelHorizontalPlacement
Label horizontal placement.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
QColor fillColor() const
Returns the color used for fills in the scalebar.
int type() const override
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
void refreshItemSize()
Refreshes an item&#39;s size by rechecking it against any possible item fixed or minimum sizes...
double height() const
Returns the scalebar height (in millimeters).
void setMaximumBarWidth(double maxWidth)
Sets the maximum width (in millimeters) for scale bar segments.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
LabelVerticalPlacement labelVerticalPlacement() const
Returns the vertical placement of text labels.
void setFillColor(const QColor &color)
Sets the color used for fills in the scalebar.
QgsRectangle extent() const
Returns the current map extent.
Layout graphical items for displaying a map.
static Q_INVOKABLE QString toAbbreviatedString(QgsUnitTypes::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
int numberOfSegments() const
Returns the number of segments included in the scalebar.
void setSize(double size)
Sets the size for rendered text.
Scalebar secondary fill color.
QgsPropertyCollection mDataDefinedProperties
const QgsLayout * layout() const
Returns the layout the object is attached to.
void setNumberOfSegments(int segments)
Sets the number of segments included in the scalebar.
double minimumBarWidth() const
Returns the minimum width (in millimeters) for scale bar segments.
void setLineCapStyle(Qt::PenCapStyle style)
Sets the cap style used when drawing the lines in the scalebar.
void resizeToMinimumWidth()
Resizes the scale bar to its minimum width, without changing the height.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
void setMapUnitsPerScaleBarUnit(double units)
Sets the number of map units per scale bar unit used by the scalebar.
QSizeF size
Destination size for scalebar.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
void setAlignment(Alignment alignment)
Sets the scalebar alignment.
QgsUnitTypes::DistanceUnit units() const
Returns the distance units used by the scalebar.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgslayoutitem.h:72
double boxContentSpace() const
Returns the spacing (margin) between the scalebar box and content in millimeters. ...
void setMinimumBarWidth(double minWidth)
Sets the minimum width (in millimeters) for scale bar segments.
double labelBarSpace() const
Returns the spacing (in millimeters) between labels and the scalebar.
QPointer< QgsLayout > mLayout
virtual void attemptResize(const QgsLayoutSize &size, bool includesFrame=false)
Attempts to resize the item to a specified target size.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setMaximumBarWidth(double width)
Sets the maximum width (in millimeters) for scale bar segments.
Degrees, for planar geographic CRS distance measurements.
Definition: qgsunittypes.h:74
void setBoxContentSpace(double space)
Sets the space (margin) between the scalebar box and content in millimeters.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
void setUnitsPerSegment(double units)
Sets the number of scalebar units per segment.
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
void setSegmentSizeMode(SegmentSizeMode mode)
Sets the size mode for scale bar segments.
QgsUnitTypes::LayoutUnit units() const
Returns the units for the size.
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
double unitsPerSegment() const
Returns the number of scalebar units per segment.
void setFillColor2(const QColor &color)
Sets the secondary color used for fills in the scalebar.
void setUnitLabel(const QString &label)
Sets the label for units.
A text format entity for QgsStyle databases.
Definition: qgsstyle.h:1034
SegmentSizeMode
Modes for setting size for scale bar segments.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
Scale bar segment size is fixed to a map unit.
QIcon icon() const override
Returns the item&#39;s icon.
LabelHorizontalPlacement labelHorizontalPlacement() const
Returns the horizontal placement of text labels.
double maximumBarWidth() const
Returns the maximum width (in millimeters) for scale bar segments.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
void setLabelHorizontalPlacement(QgsScaleBarSettings::LabelHorizontalPlacement placement)
Sets the horizontal placement of text labels.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
QgsTextFormat & textFormat()
Returns the text format used for drawing text in the scalebar.
Q_DECL_DEPRECATED void setFont(const QFont &font)
Sets the font used for drawing text in the scalebar.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:44
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:66
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
virtual QString displayName() const
Gets item display name.
void setHeight(double height)
Sets the scalebar height (in millimeters).
void setTextFormat(const QgsTextFormat &format)
Sets the text format used for drawing text in the scalebar.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:650
Unknown distance unit.
Definition: qgsunittypes.h:77
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
QgsLayoutItemScaleBar(QgsLayout *layout)
Constructor for QgsLayoutItemScaleBar, with the specified parent layout.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item&#39;s contents using the specified item render context.
Points (e.g., for font sizes)
Definition: qgsunittypes.h:151
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
void setUnits(QgsUnitTypes::DistanceUnit units)
Sets the distance units used by the scalebar.
void setLineJoinStyle(Qt::PenJoinStyle style)
Sets the join style used when drawing the lines in the scalebar.
double scale() const
Returns the map scale.
void setLineWidth(double width)
Sets the line width in millimeters for lines in the scalebar.
virtual QString uuid() const
Returns the item identification string.
This class represents a coordinate reference system (CRS).
void setLabelBarSpace(double space)
Sets the spacing (in millimeters) between labels and the scalebar.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void applyDefaultSettings()
Applies the default scalebar settings to the scale bar.
void setLabelHorizontalPlacement(LabelHorizontalPlacement placement)
Sets the horizontal placement of text labels.
void setBrush2(const QBrush &brush)
Sets the secondary brush used for filling the scalebar.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
A layout item subclass for scale bars.
void setNumberOfSegmentsLeft(int segments)
Sets the number of segments included in the left part of the scalebar.
double unitsPerSegment() const
Returns the number of scalebar units per segment.
Q_DECL_DEPRECATED QColor fontColor() const
Returns the color used for drawing text in the scalebar.
Qt::PenCapStyle lineCapStyle() const
Returns the cap style used for drawing lines in the scalebar.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
void setNumberOfSegmentsLeft(int segments)
Sets the number of segments included in the left part of the scalebar.
QBrush brush2() const
Returns the secondary brush for the scalebar.
void setTextFormat(const QgsTextFormat &format)
Sets the text format used for drawing text in the scalebar.
static QString encodePenCapStyle(Qt::PenCapStyle style)
Terrestrial miles.
Definition: qgsunittypes.h:73
Container for all settings relating to text rendering.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:40
Qt::PenJoinStyle lineJoinStyle() const
Returns the join style used for drawing lines in the scalebar.
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
QgsTextFormat textFormat() const
Returns the text format used for drawing text in the scalebar.
void setLabelVerticalPlacement(QgsScaleBarSettings::LabelVerticalPlacement placement)
Sets the vertical placement of text labels.
int numberOfSegmentsLeft() const
Returns the number of segments included in the left part of the scalebar.
void setUnits(QgsUnitTypes::DistanceUnit units)
Sets the distance units used by the scalebar.
void changed()
Emitted when the object&#39;s properties change.
DataDefinedProperty
Data defined properties for different item types.
void setUnitsPerSegment(double units)
Sets the number of scalebar units per segment.
void setBrush(const QBrush &brush)
Sets the primary brush used for filling the scalebar.
QFont font() const
Returns the font used for rendering text.
Q_DECL_DEPRECATED void setFont(const QFont &font)
Sets the font used for drawing text in the scalebar.
void setUnitLabel(const QString &label)
Sets the label for units.
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
Contains information relating to the style entity currently being visited.
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
void applyDefaultSize(QgsUnitTypes::DistanceUnit units=QgsUnitTypes::DistanceMeters)
Applies the default size to the scale bar (scale bar 1/5 of map item width)
void setWidth(const double width)
Sets the width for the size.
Definition: qgslayoutsize.h:83
void setNumberOfSegments(int segments)
Sets the number of segments included in the scalebar.
static QgsLayoutItemScaleBar * create(QgsLayout *layout)
Returns a new scale bar item for the specified layout.
QgsUnitTypes::DistanceUnit units() const
Returns the distance units used by the scalebar.
All properties for item.
ExportLayerBehavior exportLayerBehavior() const override
Returns the behavior of this item during exporting to layered exports (e.g.
Contains parameters regarding scalebar calculations.