Begin porting scalebar item

This commit is contained in:
Nyall Dawson 2017-11-20 15:13:26 +10:00
parent 604e51d390
commit 8f5e0cb126
11 changed files with 1871 additions and 1 deletions

View File

@ -422,6 +422,7 @@
%Include layout/qgslayoutitempolygon.sip
%Include layout/qgslayoutitempolyline.sip
%Include layout/qgslayoutitemregistry.sip
%Include layout/qgslayoutitemscalebar.sip
%Include layout/qgslayoutitemshape.sip
%Include layout/qgslayoutmodel.sip
%Include layout/qgslayoutmultiframe.sip

View File

@ -173,6 +173,7 @@ class QgsLayoutItemRegistry : QObject
LayoutShape,
LayoutPolygon,
LayoutPolyline,
LayoutScaleBar,
LayoutFrame,
// known

View File

@ -0,0 +1,447 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutitemscalebar.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutItemScaleBar: QgsLayoutItem
{
%Docstring
A layout item subclass for scale bars.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutitemscalebar.h"
%End
public:
QgsLayoutItemScaleBar( QgsLayout *layout );
%Docstring
Constructor for QgsLayoutItemScaleBar, with the specified parent ``layout``.
%End
~QgsLayoutItemScaleBar();
virtual int type() const;
virtual QString stringType() const;
static QgsLayoutItemScaleBar *create( QgsLayout *layout ) /Factory/;
%Docstring
Returns a new scale bar item for the specified ``layout``.
The caller takes responsibility for deleting the returned object.
:rtype: QgsLayoutItemScaleBar
%End
int numberOfSegments() const;
%Docstring
Returns the number of segments included in the scalebar.
.. seealso:: setNumberOfSegments()
.. seealso:: numberOfSegmentsLeft()
:rtype: int
%End
void setNumberOfSegments( int segments );
%Docstring
Sets the number of ``segments`` included in the scalebar.
.. seealso:: numberOfSegments()
.. seealso:: setNumberOfSegmentsLeft()
%End
int numberOfSegmentsLeft() const;
%Docstring
Returns the number of segments included in the left part of the scalebar.
.. seealso:: setNumberOfSegmentsLeft()
.. seealso:: numberOfSegments()
:rtype: int
%End
void setNumberOfSegmentsLeft( int segments );
%Docstring
Sets the number of ``segments`` included in the left part of the scalebar.
.. seealso:: numberOfSegmentsLeft()
.. seealso:: setNumberOfSegments()
%End
double unitsPerSegment() const;
%Docstring
Returns the number of scalebar units per segment.
.. seealso:: setUnitsPerSegment()
:rtype: float
%End
void setUnitsPerSegment( double units );
%Docstring
Sets the number of scalebar ``units`` per segment.
.. seealso:: unitsPerSegment()
%End
QgsScaleBarSettings::SegmentSizeMode segmentSizeMode() const;
%Docstring
Returns the size mode for the scale bar segments.
.. seealso:: setSegmentSizeMode()
.. seealso:: minBarWidth()
.. seealso:: maxBarWidth()
:rtype: QgsScaleBarSettings.SegmentSizeMode
%End
void setSegmentSizeMode( QgsScaleBarSettings::SegmentSizeMode mode );
%Docstring
Sets the size ``mode`` for scale bar segments.
.. seealso:: segmentSizeMode()
.. seealso:: setMinimumBarWidth()
.. seealso:: setMaximumBarWidth()
%End
double minimumBarWidth() const;
%Docstring
Returns the minimum width (in millimeters) for scale bar segments. This
property is only effective if the segmentSizeMode() is set
to SegmentSizeFitWidth.
.. seealso:: segmentSizeMode()
.. seealso:: setMinimumBarWidth()
.. seealso:: maximumBarWidth()
:rtype: float
%End
void setMinimumBarWidth( double minWidth );
%Docstring
Sets the minimum ``width`` (in millimeters) for scale bar segments. This
property is only effective if the segmentSizeMode() is set
to SegmentSizeFitWidth.
.. seealso:: minimumBarWidth()
.. seealso:: setMaximumBarWidth()
.. seealso:: setSegmentSizeMode()
%End
double maximumBarWidth() const;
%Docstring
Returns the maximum width (in millimeters) for scale bar segments. This
property is only effective if the segmentSizeMode() is set
to SegmentSizeFitWidth.
.. seealso:: segmentSizeMode()
.. seealso:: setMaximumBarWidth()
.. seealso:: minimumBarWidth()
:rtype: float
%End
void setMaximumBarWidth( double maxWidth );
%Docstring
Sets the maximum ``width`` (in millimeters) for scale bar segments. This
property is only effective if the segmentSizeMode() is set
to SegmentSizeFitWidth.
.. seealso:: minimumBarWidth()
.. seealso:: setMinimumBarWidth()
.. seealso:: setSegmentSizeMode()
%End
double mapUnitsPerScaleBarUnit() const;
%Docstring
Returns the number of map units per scale bar unit used by the scalebar.
.. seealso:: setMapUnitsPerScaleBarUnit()
:rtype: float
%End
void setMapUnitsPerScaleBarUnit( double units );
%Docstring
Sets the number of map ``units`` per scale bar unit used by the scalebar.
.. seealso:: mapUnitsPerScaleBarUnit()
%End
QString unitLabel() const;
%Docstring
Returns the label for units.
.. seealso:: setUnitLabel()
:rtype: str
%End
void setUnitLabel( const QString &label );
%Docstring
Sets the ``label`` for units.
.. seealso:: unitLabel()
%End
QFont font() const;
%Docstring
Returns the font used for drawing text in the scalebar.
.. seealso:: setFont()
:rtype: QFont
%End
void setFont( const QFont &font );
%Docstring
Sets the ``font`` used for drawing text in the scalebar.
.. seealso:: setFont()
%End
QColor fontColor() const;
%Docstring
Returns the color used for drawing text in the scalebar.
.. seealso:: setFontColor()
.. seealso:: font()
:rtype: QColor
%End
void setFontColor( const QColor &color );
%Docstring
Sets the ``color`` used for drawing text in the scalebar.
.. seealso:: fontColor()
.. seealso:: setFont()
%End
QColor fillColor() const;
%Docstring
Returns the color used for fills in the scalebar.
.. seealso:: setFillColor()
.. seealso:: fillColor2()
:rtype: QColor
%End
void setFillColor( const QColor &color );
%Docstring
Sets the ``color`` used for fills in the scalebar.
.. seealso:: fillColor()
.. seealso:: setFillColor2()
%End
QColor fillColor2() const;
%Docstring
Returns the secondary color used for fills in the scalebar.
.. seealso:: setFillColor2()
.. seealso:: fillColor()
:rtype: QColor
%End
void setFillColor2( const QColor &color );
%Docstring
Sets the secondary ``color`` used for fills in the scalebar.
.. seealso:: fillColor2()
.. seealso:: setFillColor2()
%End
QColor lineColor() const;
%Docstring
Returns the color used for lines in the scalebar.
.. seealso:: setLineColor()
:rtype: QColor
%End
void setLineColor( const QColor &color );
%Docstring
Sets the ``color`` used for lines in the scalebar.
.. seealso:: lineColor()
%End
double lineWidth() const;
%Docstring
Returns the line width in millimeters for lines in the scalebar.
.. seealso:: setLineWidth()
:rtype: float
%End
void setLineWidth( double width );
%Docstring
Sets the line ``width`` in millimeters for lines in the scalebar.
.. seealso:: lineWidth()
%End
QPen pen() const;
%Docstring
Returns the pen used for drawing outlines in the scalebar.
.. seealso:: setPen()
.. seealso:: brush()
:rtype: QPen
%End
QBrush brush() const;
%Docstring
Returns the primary brush for the scalebar.
:return: QBrush used for filling the scalebar
.. seealso:: setBrush
.. seealso:: brush2
.. seealso:: pen
:rtype: QBrush
%End
QBrush brush2() const;
%Docstring
Returns the secondary brush for the scalebar. This is used for alternating color style scalebars, such
as single and double box styles.
:return: QBrush used for secondary color areas
.. seealso:: setBrush2
.. seealso:: brush
:rtype: QBrush
%End
double height() const;
%Docstring
Returns the scalebar height (in millimeters).
.. seealso:: setHeight()
:rtype: float
%End
void setHeight( double height );
%Docstring
Sets the scalebar ``height`` (in millimeters).
.. seealso:: height()
%End
void setMap( QgsLayoutItemMap *map );
%Docstring
Sets the ``map`` item linked to the scalebar.
.. seealso:: map()
%End
QgsLayoutItemMap *map() const;
%Docstring
Returns the map item linked to the scalebar.
.. seealso:: setMap()
:rtype: QgsLayoutItemMap
%End
double labelBarSpace() const;
%Docstring
Returns the spacing (in millimeters) between labels and the scalebar.
.. seealso:: setLabelBarSpace()
:rtype: float
%End
void setLabelBarSpace( double space );
%Docstring
Sets the spacing (in millimeters) between labels and the scalebar.
.. seealso:: labelBarSpace()
%End
double boxContentSpace() const;
%Docstring
Returns the spacing (margin) between the scalebar box and content in millimeters.
.. seealso:: setBoxContentSpace()
:rtype: float
%End
void setBoxContentSpace( double space );
%Docstring
Sets the ``space`` (margin) between the scalebar box and content in millimeters.
.. seealso:: boxContentSpace()
%End
QgsScaleBarSettings::Alignment alignment() const;
%Docstring
Returns the scalebar alignment.
.. seealso:: setAlignment()
:rtype: QgsScaleBarSettings.Alignment
%End
void setAlignment( QgsScaleBarSettings::Alignment alignment );
%Docstring
Sets the scalebar ``alignment``.
.. seealso:: alignment()
%End
QgsUnitTypes::DistanceUnit units() const;
%Docstring
Returns the distance units used by the scalebar.
.. seealso:: setUnits()
:rtype: QgsUnitTypes.DistanceUnit
%End
void setUnits( QgsUnitTypes::DistanceUnit units );
%Docstring
Sets the distance ``units`` used by the scalebar.
.. seealso:: units()
%End
Qt::PenJoinStyle lineJoinStyle() const;
%Docstring
Returns the join style used for drawing lines in the scalebar.
.. seealso:: setLineJoinStyle()
:rtype: Qt.PenJoinStyle
%End
void setLineJoinStyle( Qt::PenJoinStyle style );
%Docstring
Sets the join ``style`` used when drawing the lines in the scalebar
.. seealso:: lineJoinStyle()
%End
Qt::PenCapStyle lineCapStyle() const;
%Docstring
Returns the cap style used for drawing lines in the scalebar.
.. seealso:: setLineCapStyle()
:rtype: Qt.PenCapStyle
%End
void setLineCapStyle( Qt::PenCapStyle style );
%Docstring
Sets the cap ``style`` used when drawing the lines in the scalebar.
.. seealso:: lineCapStyle()
%End
void applyDefaultSettings();
%Docstring
Applies the default scalebar settings to the scale bar.
.. seealso:: applyDefaultSize()
%End
void applyDefaultSize( QgsUnitTypes::DistanceUnit units = QgsUnitTypes::DistanceMeters );
%Docstring
Applies the default size to the scale bar (scale bar 1/5 of map item width)
.. seealso:: applyDefaultSettings()
%End
void setStyle( const QString &name );
%Docstring
Sets the scale bar style by ``name``.
The ``name`` parameter gives the (untranslated) style name.
Possibilities are: 'Single Box', 'Double Box', 'Line Ticks Middle',
'Line Ticks Down', 'Line Ticks Up', 'Numeric'
.. seealso:: style()
%End
QString style() const;
%Docstring
Returns the scale bar style name.
.. seealso:: setStyle()
:rtype: str
%End
void adjustBoxSize();
%Docstring
Sets the scale bar box size to a size suitable for the scalebar content.
%End
void update();
%Docstring
Adjusts the scale bar box size and updates the item.
%End
virtual void refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties );
protected:
virtual void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = 0 );
virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutitemscalebar.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -184,6 +184,12 @@ class QgsLayoutMultiFrame: QgsLayoutObject, QgsLayoutUndoObjectInterface
:rtype: bool
%End
QList<QgsLayoutFrame *> frames() const;
%Docstring
Returns a list of all child frames for this multiframe.
.. seealso:: frameCount()
:rtype: list of QgsLayoutFrame
%End
int frameCount() const;
%Docstring
@ -199,6 +205,14 @@ class QgsLayoutMultiFrame: QgsLayoutObject, QgsLayoutUndoObjectInterface
:rtype: QgsLayoutFrame
%End
int frameIndex( QgsLayoutFrame *frame ) const;
%Docstring
Returns the index of a ``frame`` within the multiframe.
:return: index for frame if found, -1 if frame not found in multiframe
.. seealso:: frame()
:rtype: int
%End
QgsLayoutFrame *createNewFrame( QgsLayoutFrame *currentFrame, QPointF pos, QSizeF size );
%Docstring
Creates a new frame and adds it to the multi frame and layout.

View File

@ -32,6 +32,7 @@
#include "qgslayoutitemlabel.h"
#include "qgslayoutlabelwidget.h"
#include "qgslayoutitemlegend.h"
#include "qgslayoutitemscalebar.h"
#include "qgslayoutlegendwidget.h"
#include "qgslayoutframe.h"
#include "qgslayoutitemhtml.h"
@ -140,6 +141,29 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
registry->addLayoutItemGuiMetadata( legendItemMetadata.release() );
// scalebar item
auto scalebarItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutScaleBar, QObject::tr( "Scale Bar" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddScalebar.svg" ) ),
[ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
{
return nullptr;//new QgsLayoutLegendWidget( qobject_cast< QgsLayoutItemLegend * >( item ) );
}, createRubberBand );
scalebarItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
{
QgsLayoutItemScaleBar *scalebar = qobject_cast< QgsLayoutItemScaleBar * >( item );
Q_ASSERT( scalebar );
QList<QgsLayoutItemMap *> mapItems;
scalebar->layout()->layoutItems( mapItems );
if ( !mapItems.isEmpty() )
{
scalebar->setMap( mapItems.at( 0 ) );
}
scalebar->applyDefaultSize();
} );
registry->addLayoutItemGuiMetadata( scalebarItemMetadata.release() );
// shape items

View File

@ -386,6 +386,7 @@ SET(QGIS_CORE_SRCS
layout/qgslayoutitempolygon.cpp
layout/qgslayoutitempolyline.cpp
layout/qgslayoutitemregistry.cpp
layout/qgslayoutitemscalebar.cpp
layout/qgslayoutitemshape.cpp
layout/qgslayoutitemundocommand.cpp
layout/qgslayoutmeasurement.cpp
@ -750,6 +751,7 @@ SET(QGIS_CORE_MOC_HDRS
layout/qgslayoutitempolygon.h
layout/qgslayoutitempolyline.h
layout/qgslayoutitemregistry.h
layout/qgslayoutitemscalebar.h
layout/qgslayoutitemshape.h
layout/qgslayoutmodel.h
layout/qgslayoutmultiframe.h

View File

@ -25,6 +25,7 @@
#include "qgslayoutitempicture.h"
#include "qgslayoutitemgroup.h"
#include "qgslayoutitemhtml.h"
#include "qgslayoutitemscalebar.h"
#include "qgslayoutframe.h"
#include "qgsgloweffect.h"
#include "qgseffectstack.h"
@ -59,6 +60,7 @@ bool QgsLayoutItemRegistry::populate()
addLayoutItemType( new QgsLayoutItemMetadata( LayoutPicture, QStringLiteral( "Picture" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddImage.svg" ) ), QgsLayoutItemPicture::create ) );
addLayoutItemType( new QgsLayoutItemMetadata( LayoutLabel, QStringLiteral( "Label" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionLabel.svg" ) ), QgsLayoutItemLabel::create ) );
addLayoutItemType( new QgsLayoutItemMetadata( LayoutLegend, QStringLiteral( "Legend" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLegend.svg" ) ), QgsLayoutItemLegend::create ) );
addLayoutItemType( new QgsLayoutItemMetadata( LayoutScaleBar, QStringLiteral( "Scale Bar" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddScalebar.svg" ) ), QgsLayoutItemScaleBar::create ) );
addLayoutItemType( new QgsLayoutItemMetadata( LayoutShape, QStringLiteral( "Shape" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), []( QgsLayout * layout )
{
QgsLayoutItemShape *shape = new QgsLayoutItemShape( layout );

View File

@ -315,6 +315,7 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
LayoutShape, //!< Shape item
LayoutPolygon, //!< Polygon shape item
LayoutPolyline, //!< Polyline shape item
LayoutScaleBar, //!< Scale bar item
LayoutFrame, //!< Frame item, part of a QgsLayoutMultiFrame object
// known multi-frame types

View File

@ -0,0 +1,919 @@
/***************************************************************************
qgslayoutitemscalebar.cpp
-------------------------
begin : November 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson 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. *
* *
***************************************************************************/
#include "qgslayoutitemscalebar.h"
#include "qgslayoutitemregistry.h"
#include "qgslayoutitemmap.h"
#include "qgslayout.h"
#include "qgslayoututils.h"
#include "qgsdistancearea.h"
#include "qgsscalebarrenderer.h"
#include "qgsdoubleboxscalebarrenderer.h"
#include "qgsmapsettings.h"
#include "qgsnumericscalebarrenderer.h"
#include "qgssingleboxscalebarrenderer.h"
#include "qgsticksscalebarrenderer.h"
#include "qgsrectangle.h"
#include "qgsproject.h"
#include "qgssymbollayerutils.h"
#include "qgsfontutils.h"
#include "qgsunittypes.h"
#include "qgssettings.h"
#include <QDomDocument>
#include <QDomElement>
#include <QFontMetricsF>
#include <QPainter>
#include <cmath>
QgsLayoutItemScaleBar::QgsLayoutItemScaleBar( QgsLayout *layout )
: QgsLayoutItem( layout )
, mSegmentMillimeters( 0.0 )
{
applyDefaultSettings();
applyDefaultSize();
}
QgsLayoutItemScaleBar::~QgsLayoutItemScaleBar()
{
delete mStyle;
}
int QgsLayoutItemScaleBar::type() const
{
return QgsLayoutItemRegistry::LayoutScaleBar;
}
QString QgsLayoutItemScaleBar::stringType() const
{
return QStringLiteral( "ItemScaleBar" );
}
QgsLayoutItemScaleBar *QgsLayoutItemScaleBar::create( QgsLayout *layout )
{
return new QgsLayoutItemScaleBar( layout );
}
void QgsLayoutItemScaleBar::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem * )
{
if ( !mStyle )
return;
mStyle->draw( context, mSettings, createScaleContext() );
}
void QgsLayoutItemScaleBar::setNumberOfSegments( int nSegments )
{
if ( !mStyle )
{
mSettings.setNumberOfSegments( nSegments );
return;
}
double width = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
mSettings.setNumberOfSegments( nSegments );
double widthAfter = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
correctXPositionAlignment( width, widthAfter );
emit changed();
}
void QgsLayoutItemScaleBar::setUnitsPerSegment( double units )
{
if ( !mStyle )
{
mSettings.setUnitsPerSegment( units );
return;
}
double width = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
mSettings.setUnitsPerSegment( units );
refreshSegmentMillimeters();
double widthAfter = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
correctXPositionAlignment( width, widthAfter );
emit changed();
}
void QgsLayoutItemScaleBar::setSegmentSizeMode( QgsScaleBarSettings::SegmentSizeMode mode )
{
if ( !mStyle )
{
mSettings.setSegmentSizeMode( mode );
return;
}
double width = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
mSettings.setSegmentSizeMode( mode );
refreshSegmentMillimeters();
double widthAfter = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
correctXPositionAlignment( width, widthAfter );
emit changed();
}
void QgsLayoutItemScaleBar::setMinimumBarWidth( double minWidth )
{
if ( !mStyle )
{
mSettings.setMinimumBarWidth( minWidth );
return;
}
double width = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
mSettings.setMinimumBarWidth( minWidth );
refreshSegmentMillimeters();
double widthAfter = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
correctXPositionAlignment( width, widthAfter );
emit changed();
}
void QgsLayoutItemScaleBar::setMaximumBarWidth( double maxWidth )
{
if ( !mStyle )
{
mSettings.setMaximumBarWidth( maxWidth );
return;
}
double width = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
mSettings.setMaximumBarWidth( maxWidth );
refreshSegmentMillimeters();
double widthAfter = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
correctXPositionAlignment( width, widthAfter );
emit changed();
}
void QgsLayoutItemScaleBar::setNumberOfSegmentsLeft( int nSegmentsLeft )
{
if ( !mStyle )
{
mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
return;
}
double width = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
double widthAfter = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
correctXPositionAlignment( width, widthAfter );
emit changed();
}
void QgsLayoutItemScaleBar::setBoxContentSpace( double space )
{
if ( !mStyle )
{
mSettings.setBoxContentSpace( space );
return;
}
double width = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
mSettings.setBoxContentSpace( space );
double widthAfter = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
correctXPositionAlignment( width, widthAfter );
emit changed();
}
void QgsLayoutItemScaleBar::setMap( QgsLayoutItemMap *map )
{
if ( mMap )
{
disconnect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateSegmentSize );
disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::invalidateCurrentMap );
}
mMap = map;
if ( !map )
{
return;
}
connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateSegmentSize );
connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::invalidateCurrentMap );
refreshSegmentMillimeters();
emit changed();
}
void QgsLayoutItemScaleBar::invalidateCurrentMap()
{
if ( !mMap )
{
return;
}
disconnect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateSegmentSize );
disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::invalidateCurrentMap );
mMap = nullptr;
}
void QgsLayoutItemScaleBar::refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property )
{
QgsExpressionContext context = createExpressionContext();
bool forceUpdate = false;
//updates data defined properties and redraws item to match
if ( property == QgsLayoutObject::ScalebarFillColor || property == QgsLayoutObject::AllProperties )
{
QBrush b = mSettings.brush();
b.setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarFillColor, context, mSettings.fillColor() ) );
mSettings.setBrush( b );
forceUpdate = true;
}
if ( property == QgsLayoutObject::ScalebarFillColor2 || property == QgsLayoutObject::AllProperties )
{
QBrush b = mSettings.brush2();
b.setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarFillColor2, context, mSettings.fillColor2() ) );
mSettings.setBrush2( b );
forceUpdate = true;
}
if ( property == QgsLayoutObject::ScalebarLineColor || property == QgsLayoutObject::AllProperties )
{
QPen p = mSettings.pen();
p.setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarLineColor, context, mSettings.lineColor() ) );
mSettings.setPen( p );
forceUpdate = true;
}
if ( property == QgsLayoutObject::ScalebarLineWidth || property == QgsLayoutObject::AllProperties )
{
QPen p = mSettings.pen();
p.setWidthF( mDataDefinedProperties.valueAsDouble( QgsLayoutObject::ScalebarLineWidth, context, mSettings.lineWidth() ) );
mSettings.setPen( p );
forceUpdate = true;
}
if ( forceUpdate )
{
update();
}
QgsLayoutItem::refreshDataDefinedProperty( property );
}
// nextNiceNumber(4573.23, d) = 5000 (d=1) -> 4600 (d=10) -> 4580 (d=100) -> 4574 (d=1000) -> etc
inline double nextNiceNumber( double a, double d = 1 )
{
double s = std::pow( 10.0, std::floor( std::log10( a ) ) ) / d;
return std::ceil( a / s ) * s;
}
// prevNiceNumber(4573.23, d) = 4000 (d=1) -> 4500 (d=10) -> 4570 (d=100) -> 4573 (d=1000) -> etc
inline double prevNiceNumber( double a, double d = 1 )
{
double s = std::pow( 10.0, std::floor( std::log10( a ) ) ) / d;
return std::floor( a / s ) * s;
}
void QgsLayoutItemScaleBar::refreshSegmentMillimeters()
{
if ( mMap )
{
//get mm dimension of composer map
QRectF composerItemRect = mMap->rect();
if ( mSettings.segmentSizeMode() == QgsScaleBarSettings::SegmentSizeFixed )
{
//calculate size depending on mNumUnitsPerSegment
mSegmentMillimeters = composerItemRect.width() / mapWidth() * mSettings.unitsPerSegment();
}
else /*if(mSegmentSizeMode == SegmentSizeFitWidth)*/
{
if ( mSettings.maximumBarWidth() < mSettings.minimumBarWidth() )
{
mSegmentMillimeters = 0;
}
else
{
double nSegments = ( mSettings.numberOfSegmentsLeft() != 0 ) + mSettings.numberOfSegments();
// unitsPerSegments which fit minBarWidth resp. maxBarWidth
double minUnitsPerSeg = ( mSettings.minimumBarWidth() * mapWidth() ) / ( nSegments * composerItemRect.width() );
double maxUnitsPerSeg = ( mSettings.maximumBarWidth() * mapWidth() ) / ( nSegments * composerItemRect.width() );
// Start with coarsest "nice" number closest to minUnitsPerSeg resp
// maxUnitsPerSeg, then proceed to finer numbers as long as neither
// lowerNiceUnitsPerSeg nor upperNiceUnitsPerSeg are are in
// [minUnitsPerSeg, maxUnitsPerSeg]
double lowerNiceUnitsPerSeg = nextNiceNumber( minUnitsPerSeg );
double upperNiceUnitsPerSeg = prevNiceNumber( maxUnitsPerSeg );
double d = 1;
while ( lowerNiceUnitsPerSeg > maxUnitsPerSeg && upperNiceUnitsPerSeg < minUnitsPerSeg )
{
d *= 10;
lowerNiceUnitsPerSeg = nextNiceNumber( minUnitsPerSeg, d );
upperNiceUnitsPerSeg = prevNiceNumber( maxUnitsPerSeg, d );
}
// Pick mNumUnitsPerSegment from {lowerNiceUnitsPerSeg, upperNiceUnitsPerSeg}, use the larger if possible
mSettings.setUnitsPerSegment( upperNiceUnitsPerSeg < minUnitsPerSeg ? lowerNiceUnitsPerSeg : upperNiceUnitsPerSeg );
mSegmentMillimeters = composerItemRect.width() / mapWidth() * mSettings.unitsPerSegment();
}
}
}
}
double QgsLayoutItemScaleBar::mapWidth() const
{
if ( !mMap )
{
return 0.0;
}
QgsRectangle mapExtent = mMap->extent();
if ( mSettings.units() == QgsUnitTypes::DistanceUnknownUnit )
{
return mapExtent.width();
}
else
{
QgsDistanceArea da;
da.setSourceCrs( mMap->crs() );
da.setEllipsoid( mLayout->project()->ellipsoid() );
QgsUnitTypes::DistanceUnit units = da.lengthUnits();
double measure = da.measureLine( QgsPointXY( mapExtent.xMinimum(), mapExtent.yMinimum() ),
QgsPointXY( mapExtent.xMaximum(), mapExtent.yMinimum() ) );
measure /= QgsUnitTypes::fromUnitToUnitFactor( mSettings.units(), units );
return measure;
}
}
QgsScaleBarRenderer::ScaleBarContext QgsLayoutItemScaleBar::createScaleContext() const
{
QgsScaleBarRenderer::ScaleBarContext scaleContext;
scaleContext.size = rect().size();
scaleContext.segmentWidth = mSegmentMillimeters;
scaleContext.scale = mMap ? mMap->scale() : 1.0;
return scaleContext;
}
void QgsLayoutItemScaleBar::setAlignment( QgsScaleBarSettings::Alignment a )
{
mSettings.setAlignment( a );
update();
emit changed();
}
void QgsLayoutItemScaleBar::setUnits( QgsUnitTypes::DistanceUnit u )
{
mSettings.setUnits( u );
refreshSegmentMillimeters();
emit changed();
}
void QgsLayoutItemScaleBar::setLineJoinStyle( Qt::PenJoinStyle style )
{
if ( mSettings.lineJoinStyle() == style )
{
//no change
return;
}
mSettings.setLineJoinStyle( style );
update();
emit changed();
}
void QgsLayoutItemScaleBar::setLineCapStyle( Qt::PenCapStyle style )
{
if ( mSettings.lineCapStyle() == style )
{
//no change
return;
}
mSettings.setLineCapStyle( style );
update();
emit changed();
}
void QgsLayoutItemScaleBar::applyDefaultSettings()
{
//style
delete mStyle;
mStyle = new QgsSingleBoxScaleBarRenderer();
//default to no background
setBackgroundEnabled( false );
//get default composer font from settings
QgsSettings settings;
QString defaultFontString = settings.value( QStringLiteral( "Composer/defaultFont" ) ).toString();
QFont f;
if ( !defaultFontString.isEmpty() )
{
f.setFamily( defaultFontString );
}
f.setPointSizeF( 12.0 );
mSettings.setFont( f );
mSettings.setUnits( QgsUnitTypes::DistanceUnknownUnit );
emit changed();
}
void QgsLayoutItemScaleBar::applyDefaultSize( QgsUnitTypes::DistanceUnit units )
{
if ( mMap )
{
setUnits( units );
double upperMagnitudeMultiplier = 1.0;
double widthInSelectedUnits = mapWidth();
double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
setUnitsPerSegment( initialUnitsPerSegment );
switch ( units )
{
case QgsUnitTypes::DistanceUnknownUnit:
{
upperMagnitudeMultiplier = 1.0;
setUnitLabel( tr( "units" ) );
break;
}
case QgsUnitTypes::DistanceMeters:
{
if ( initialUnitsPerSegment > 1000.0 )
{
upperMagnitudeMultiplier = 1000.0;
setUnitLabel( tr( "km" ) );
}
else
{
upperMagnitudeMultiplier = 1.0;
setUnitLabel( tr( "m" ) );
}
break;
}
case QgsUnitTypes::DistanceFeet:
{
if ( initialUnitsPerSegment > 5419.95 )
{
upperMagnitudeMultiplier = 5419.95;
setUnitLabel( tr( "miles" ) );
}
else
{
upperMagnitudeMultiplier = 1.0;
setUnitLabel( tr( "ft" ) );
}
break;
}
default:
setUnitLabel( QgsUnitTypes::toAbbreviatedString( units ) );
upperMagnitudeMultiplier = 1;
break;
}
double segmentWidth = initialUnitsPerSegment / upperMagnitudeMultiplier;
int segmentMagnitude = std::floor( std::log10( segmentWidth ) );
double unitsPerSegment = upperMagnitudeMultiplier * ( std::pow( 10.0, segmentMagnitude ) );
double multiplier = std::floor( ( widthInSelectedUnits / ( unitsPerSegment * 10.0 ) ) / 2.5 ) * 2.5;
if ( multiplier > 0 )
{
unitsPerSegment = unitsPerSegment * multiplier;
}
setUnitsPerSegment( unitsPerSegment );
setMapUnitsPerScaleBarUnit( upperMagnitudeMultiplier );
setNumberOfSegments( 4 );
setNumberOfSegmentsLeft( 2 );
}
refreshSegmentMillimeters();
adjustBoxSize();
emit changed();
}
void QgsLayoutItemScaleBar::adjustBoxSize()
{
if ( !mStyle )
{
return;
}
QRectF box = QRectF( pos(), mStyle->calculateBoxSize( mSettings, createScaleContext() ) );
if ( rect().height() > box.height() )
{
//keep user specified item height if higher than minimum scale bar height
box.setHeight( rect().height() );
}
#if 0 //TODO
//update rect for data defined size and position
QRectF newRect = evalItemRect( box, true );
//scale bars have a minimum size, respect that regardless of data defined settings
if ( newRect.width() < box.width() )
{
newRect.setWidth( box.width() );
}
if ( newRect.height() < box.height() )
{
newRect.setHeight( box.height() );
}
QgsLayoutItem::setSceneRect( newRect );
#endif
}
#if 0 //TODO
void QgsLayoutItemScaleBar::setSceneRect( const QRectF &rectangle )
{
QRectF box = QRectF( pos(), mStyle->calculateBoxSize( mSettings, createScaleContext() ) );
if ( rectangle.height() > box.height() )
{
//keep user specified item height if higher than minimum scale bar height
box.setHeight( rectangle.height() );
}
box.moveTopLeft( rectangle.topLeft() );
//update rect for data defined size and position
QRectF newRect = evalItemRect( rectangle );
//scale bars have a minimum size, respect that regardless of data defined settings
if ( newRect.width() < box.width() )
{
newRect.setWidth( box.width() );
}
if ( newRect.height() < box.height() )
{
newRect.setHeight( box.height() );
}
QgsComposerItem::setSceneRect( newRect );
}
#endif
void QgsLayoutItemScaleBar::update()
{
//Don't adjust box size for numeric scale bars:
if ( mStyle && mStyle->name() != QLatin1String( "Numeric" ) )
{
adjustBoxSize();
}
QgsLayoutItem::update();
}
void QgsLayoutItemScaleBar::updateSegmentSize()
{
if ( !mStyle )
{
return;
}
double width = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
refreshSegmentMillimeters();
double widthAfter = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
correctXPositionAlignment( width, widthAfter );
update();
emit changed();
}
void QgsLayoutItemScaleBar::setStyle( const QString &styleName )
{
delete mStyle;
mStyle = nullptr;
//switch depending on style name
if ( styleName == QLatin1String( "Single Box" ) )
{
mStyle = new QgsSingleBoxScaleBarRenderer();
}
else if ( styleName == QLatin1String( "Double Box" ) )
{
mStyle = new QgsDoubleBoxScaleBarRenderer();
}
else if ( styleName == QLatin1String( "Line Ticks Middle" ) || styleName == QLatin1String( "Line Ticks Down" ) || styleName == QLatin1String( "Line Ticks Up" ) )
{
QgsTicksScaleBarRenderer *tickStyle = new QgsTicksScaleBarRenderer();
if ( styleName == QLatin1String( "Line Ticks Middle" ) )
{
tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksMiddle );
}
else if ( styleName == QLatin1String( "Line Ticks Down" ) )
{
tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksDown );
}
else if ( styleName == QLatin1String( "Line Ticks Up" ) )
{
tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksUp );
}
mStyle = tickStyle;
}
else if ( styleName == QLatin1String( "Numeric" ) )
{
mStyle = new QgsNumericScaleBarRenderer();
}
emit changed();
}
QString QgsLayoutItemScaleBar::style() const
{
if ( mStyle )
{
return mStyle->name();
}
else
{
return QString();
}
}
QFont QgsLayoutItemScaleBar::font() const
{
return mSettings.font();
}
void QgsLayoutItemScaleBar::setFont( const QFont &font )
{
mSettings.setFont( font );
update();
emit changed();
}
bool QgsLayoutItemScaleBar::writePropertiesToElement( QDomElement &composerScaleBarElem, QDomDocument &doc, const QgsReadWriteContext & ) const
{
composerScaleBarElem.setAttribute( QStringLiteral( "height" ), QString::number( mSettings.height() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "labelBarSpace" ), QString::number( mSettings.labelBarSpace() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "boxContentSpace" ), QString::number( mSettings.boxContentSpace() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "numSegments" ), mSettings.numberOfSegments() );
composerScaleBarElem.setAttribute( QStringLiteral( "numSegmentsLeft" ), mSettings.numberOfSegmentsLeft() );
composerScaleBarElem.setAttribute( QStringLiteral( "numUnitsPerSegment" ), QString::number( mSettings.unitsPerSegment() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "segmentSizeMode" ), mSettings.segmentSizeMode() );
composerScaleBarElem.setAttribute( QStringLiteral( "minBarWidth" ), mSettings.minimumBarWidth() );
composerScaleBarElem.setAttribute( QStringLiteral( "maxBarWidth" ), mSettings.maximumBarWidth() );
composerScaleBarElem.setAttribute( QStringLiteral( "segmentMillimeters" ), QString::number( mSegmentMillimeters ) );
composerScaleBarElem.setAttribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QString::number( mSettings.mapUnitsPerScaleBarUnit() ) );
composerScaleBarElem.appendChild( QgsFontUtils::toXmlElement( mSettings.font(), doc, QStringLiteral( "scaleBarFont" ) ) );
composerScaleBarElem.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mSettings.lineWidth() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "unitLabel" ), mSettings.unitLabel() );
composerScaleBarElem.setAttribute( QStringLiteral( "unitType" ), QgsUnitTypes::encodeUnit( mSettings.units() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "lineJoinStyle" ), QgsSymbolLayerUtils::encodePenJoinStyle( mSettings.lineJoinStyle() ) );
composerScaleBarElem.setAttribute( QStringLiteral( "lineCapStyle" ), QgsSymbolLayerUtils::encodePenCapStyle( mSettings.lineCapStyle() ) );
//style
if ( mStyle )
{
composerScaleBarElem.setAttribute( QStringLiteral( "style" ), mStyle->name() );
}
//map id
if ( mMap )
{
composerScaleBarElem.setAttribute( QStringLiteral( "mapId" ), mMap->id() );
}
//colors
//fill color
QDomElement fillColorElem = doc.createElement( QStringLiteral( "fillColor" ) );
fillColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor().red() ) );
fillColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor().green() ) );
fillColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor().blue() ) );
fillColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor().alpha() ) );
composerScaleBarElem.appendChild( fillColorElem );
//fill color 2
QDomElement fillColor2Elem = doc.createElement( QStringLiteral( "fillColor2" ) );
fillColor2Elem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor2().red() ) );
fillColor2Elem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor2().green() ) );
fillColor2Elem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor2().blue() ) );
fillColor2Elem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor2().alpha() ) );
composerScaleBarElem.appendChild( fillColor2Elem );
//pen color
QDomElement strokeColorElem = doc.createElement( QStringLiteral( "strokeColor" ) );
strokeColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.lineColor().red() ) );
strokeColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.lineColor().green() ) );
strokeColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.lineColor().blue() ) );
strokeColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.lineColor().alpha() ) );
composerScaleBarElem.appendChild( strokeColorElem );
//font color
QDomElement fontColorElem = doc.createElement( QStringLiteral( "textColor" ) );
fontColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fontColor().red() ) );
fontColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fontColor().green() ) );
fontColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fontColor().blue() ) );
fontColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fontColor().alpha() ) );
composerScaleBarElem.appendChild( fontColorElem );
//alignment
composerScaleBarElem.setAttribute( QStringLiteral( "alignment" ), QString::number( static_cast< int >( mSettings.alignment() ) ) );
return true;
}
bool QgsLayoutItemScaleBar::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
{
mSettings.setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
mSettings.setLabelBarSpace( itemElem.attribute( QStringLiteral( "labelBarSpace" ), QStringLiteral( "3.0" ) ).toDouble() );
mSettings.setBoxContentSpace( itemElem.attribute( QStringLiteral( "boxContentSpace" ), QStringLiteral( "1.0" ) ).toDouble() );
mSettings.setNumberOfSegments( itemElem.attribute( QStringLiteral( "numSegments" ), QStringLiteral( "2" ) ).toInt() );
mSettings.setNumberOfSegmentsLeft( itemElem.attribute( QStringLiteral( "numSegmentsLeft" ), QStringLiteral( "0" ) ).toInt() );
mSettings.setUnitsPerSegment( itemElem.attribute( QStringLiteral( "numUnitsPerSegment" ), QStringLiteral( "1.0" ) ).toDouble() );
mSettings.setSegmentSizeMode( static_cast<QgsScaleBarSettings::SegmentSizeMode>( itemElem.attribute( QStringLiteral( "segmentSizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
mSettings.setMinimumBarWidth( itemElem.attribute( QStringLiteral( "minBarWidth" ), QStringLiteral( "50" ) ).toDouble() );
mSettings.setMaximumBarWidth( itemElem.attribute( QStringLiteral( "maxBarWidth" ), QStringLiteral( "150" ) ).toDouble() );
mSegmentMillimeters = itemElem.attribute( QStringLiteral( "segmentMillimeters" ), QStringLiteral( "0.0" ) ).toDouble();
mSettings.setMapUnitsPerScaleBarUnit( itemElem.attribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QStringLiteral( "1.0" ) ).toDouble() );
mSettings.setLineWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "0.3" ) ).toDouble() );
mSettings.setUnitLabel( itemElem.attribute( QStringLiteral( "unitLabel" ) ) );
mSettings.setLineJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "lineJoinStyle" ), QStringLiteral( "miter" ) ) ) );
mSettings.setLineCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( itemElem.attribute( QStringLiteral( "lineCapStyle" ), QStringLiteral( "square" ) ) ) );
QFont f;
if ( !QgsFontUtils::setFromXmlChildNode( f, itemElem, QStringLiteral( "scaleBarFont" ) ) )
{
f.fromString( itemElem.attribute( QStringLiteral( "font" ), QLatin1String( "" ) ) );
}
mSettings.setFont( f );
//colors
//fill color
QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "fillColor" ) );
if ( !fillColorList.isEmpty() )
{
QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
bool redOk, greenOk, blueOk, alphaOk;
int fillRed, fillGreen, fillBlue, fillAlpha;
fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
if ( redOk && greenOk && blueOk && alphaOk )
{
mSettings.setFillColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
}
}
else
{
mSettings.setFillColor( QColor( itemElem.attribute( QStringLiteral( "brushColor" ), QStringLiteral( "#000000" ) ) ) );
}
//fill color 2
QDomNodeList fillColor2List = itemElem.elementsByTagName( QStringLiteral( "fillColor2" ) );
if ( !fillColor2List.isEmpty() )
{
QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
bool redOk, greenOk, blueOk, alphaOk;
int fillRed, fillGreen, fillBlue, fillAlpha;
fillRed = fillColor2Elem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
fillGreen = fillColor2Elem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
fillBlue = fillColor2Elem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
fillAlpha = fillColor2Elem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
if ( redOk && greenOk && blueOk && alphaOk )
{
mSettings.setFillColor2( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
}
}
else
{
mSettings.setFillColor2( QColor( itemElem.attribute( QStringLiteral( "brush2Color" ), QStringLiteral( "#ffffff" ) ) ) );
}
//stroke color
QDomNodeList strokeColorList = itemElem.elementsByTagName( QStringLiteral( "strokeColor" ) );
if ( !strokeColorList.isEmpty() )
{
QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
bool redOk, greenOk, blueOk, alphaOk;
int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
strokeRed = strokeColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
strokeGreen = strokeColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
strokeBlue = strokeColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
strokeAlpha = strokeColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
if ( redOk && greenOk && blueOk && alphaOk )
{
mSettings.setLineColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
QPen p = mSettings.pen();
p.setColor( mSettings.lineColor() );
mSettings.setPen( p );
}
}
else
{
mSettings.setLineColor( QColor( itemElem.attribute( QStringLiteral( "penColor" ), QStringLiteral( "#000000" ) ) ) );
QPen p = mSettings.pen();
p.setColor( mSettings.lineColor() );
mSettings.setPen( p );
}
//font color
QDomNodeList textColorList = itemElem.elementsByTagName( QStringLiteral( "textColor" ) );
if ( !textColorList.isEmpty() )
{
QDomElement textColorElem = textColorList.at( 0 ).toElement();
bool redOk, greenOk, blueOk, alphaOk;
int textRed, textGreen, textBlue, textAlpha;
textRed = textColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
textGreen = textColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
textBlue = textColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
textAlpha = textColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
if ( redOk && greenOk && blueOk && alphaOk )
{
mSettings.setFontColor( QColor( textRed, textGreen, textBlue, textAlpha ) );
}
}
else
{
QColor c;
c.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
mSettings.setFontColor( c );
}
//style
delete mStyle;
mStyle = nullptr;
QString styleString = itemElem.attribute( QStringLiteral( "style" ), QLatin1String( "" ) );
setStyle( tr( styleString.toLocal8Bit().data() ) );
if ( itemElem.attribute( QStringLiteral( "unitType" ) ).isEmpty() )
{
QgsUnitTypes::DistanceUnit u = QgsUnitTypes::DistanceUnknownUnit;
switch ( itemElem.attribute( QStringLiteral( "units" ) ).toInt() )
{
case 0:
u = QgsUnitTypes::DistanceUnknownUnit;
break;
case 1:
u = QgsUnitTypes::DistanceMeters;
break;
case 2:
u = QgsUnitTypes::DistanceFeet;
break;
case 3:
u = QgsUnitTypes::DistanceNauticalMiles;
break;
}
mSettings.setUnits( u );
}
else
{
mSettings.setUnits( QgsUnitTypes::decodeDistanceUnit( itemElem.attribute( QStringLiteral( "unitType" ) ) ) );
}
mSettings.setAlignment( static_cast< QgsScaleBarSettings::Alignment >( itemElem.attribute( QStringLiteral( "alignment" ), QStringLiteral( "0" ) ).toInt() ) );
//map
#if 0 //TODO
int mapId = itemElem.attribute( QStringLiteral( "mapId" ), QStringLiteral( "-1" ) ).toInt();
if ( mapId >= 0 )
{
const QgsLayoutItemMap *composerMap = mComposition->getComposerMapById( mapId );
mMap = const_cast< QgsComposerMap *>( composerMap );
if ( mMap )
{
connect( mMap, &QgsComposerMap::extentChanged, this, &QgsLayoutItemScaleBar::updateSegmentSize );
connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::invalidateCurrentMap );
}
}
#endif
QString mapId = itemElem.attribute( QStringLiteral( "mapUuid" ) );
if ( !mLayout || mapId.isEmpty() )
{
mMap = nullptr;
}
else
{
invalidateCurrentMap();
mMap = qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mapId ) );
if ( mMap )
{
connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateSegmentSize );
connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::invalidateCurrentMap );
}
}
updateSegmentSize();
return true;
}
void QgsLayoutItemScaleBar::correctXPositionAlignment( double width, double widthAfter )
{
//Don't adjust position for numeric scale bars:
if ( mStyle->name() == QLatin1String( "Numeric" ) )
{
return;
}
#if 0 //TODO
if ( mSettings.alignment() == QgsScaleBarSettings::AlignMiddle )
{
move( -( widthAfter - width ) / 2.0, 0 );
}
else if ( mSettings.alignment() == QgsScaleBarSettings::AlignRight )
{
move( -( widthAfter - width ), 0 );
}
#endif
}

View File

@ -0,0 +1,459 @@
/***************************************************************************
qgslayoutitemscalebar.h
------------------------
begin : November 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson 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 QGSLAYOUTITEMSCALEBAR_H
#define QGSLAYOUTITEMSCALEBAR_H
#include "qgis_core.h"
#include "qgis.h"
#include "qgslayoutitem.h"
#include "scalebar/qgsscalebarsettings.h"
#include "scalebar/qgsscalebarrenderer.h"
#include <QFont>
#include <QPen>
#include <QColor>
class QgsLayoutItemMap;
/**
* \ingroup core
* A layout item subclass for scale bars.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutItemScaleBar: public QgsLayoutItem
{
Q_OBJECT
public:
/**
* Constructor for QgsLayoutItemScaleBar, with the specified parent \a layout.
*/
QgsLayoutItemScaleBar( QgsLayout *layout );
~QgsLayoutItemScaleBar();
int type() const override;
QString stringType() const override;
/**
* Returns a new scale bar item for the specified \a layout.
*
* The caller takes responsibility for deleting the returned object.
*/
static QgsLayoutItemScaleBar *create( QgsLayout *layout ) SIP_FACTORY;
/**
* Returns the number of segments included in the scalebar.
* \see setNumberOfSegments()
* \see numberOfSegmentsLeft()
*/
int numberOfSegments() const { return mSettings.numberOfSegments(); }
/**
* Sets the number of \a segments included in the scalebar.
* \see numberOfSegments()
* \see setNumberOfSegmentsLeft()
*/
void setNumberOfSegments( int segments );
/**
* Returns the number of segments included in the left part of the scalebar.
* \see setNumberOfSegmentsLeft()
* \see numberOfSegments()
*/
int numberOfSegmentsLeft() const { return mSettings.numberOfSegmentsLeft(); }
/**
* Sets the number of \a segments included in the left part of the scalebar.
* \see numberOfSegmentsLeft()
* \see setNumberOfSegments()
*/
void setNumberOfSegmentsLeft( int segments );
/**
* Returns the number of scalebar units per segment.
* \see setUnitsPerSegment()
*/
double unitsPerSegment() const { return mSettings.unitsPerSegment(); }
/**
* Sets the number of scalebar \a units per segment.
* \see unitsPerSegment()
*/
void setUnitsPerSegment( double units );
/**
* Returns the size mode for the scale bar segments.
* \see setSegmentSizeMode()
* \see minBarWidth()
* \see maxBarWidth()
*/
QgsScaleBarSettings::SegmentSizeMode segmentSizeMode() const { return mSettings.segmentSizeMode(); }
/**
* Sets the size \a mode for scale bar segments.
* \see segmentSizeMode()
* \see setMinimumBarWidth()
* \see setMaximumBarWidth()
*/
void setSegmentSizeMode( QgsScaleBarSettings::SegmentSizeMode mode );
/**
* Returns the minimum width (in millimeters) for scale bar segments. This
* property is only effective if the segmentSizeMode() is set
* to SegmentSizeFitWidth.
* \see segmentSizeMode()
* \see setMinimumBarWidth()
* \see maximumBarWidth()
*/
double minimumBarWidth() const { return mSettings.minimumBarWidth(); }
/**
* Sets the minimum \a width (in millimeters) for scale bar segments. This
* property is only effective if the segmentSizeMode() is set
* to SegmentSizeFitWidth.
* \see minimumBarWidth()
* \see setMaximumBarWidth()
* \see setSegmentSizeMode()
*/
void setMinimumBarWidth( double minWidth );
/**
* Returns the maximum width (in millimeters) for scale bar segments. This
* property is only effective if the segmentSizeMode() is set
* to SegmentSizeFitWidth.
* \see segmentSizeMode()
* \see setMaximumBarWidth()
* \see minimumBarWidth()
*/
double maximumBarWidth() const { return mSettings.maximumBarWidth(); }
/**
* Sets the maximum \a width (in millimeters) for scale bar segments. This
* property is only effective if the segmentSizeMode() is set
* to SegmentSizeFitWidth.
* \see minimumBarWidth()
* \see setMinimumBarWidth()
* \see setSegmentSizeMode()
*/
void setMaximumBarWidth( double maxWidth );
/**
* Returns the number of map units per scale bar unit used by the scalebar.
* \see setMapUnitsPerScaleBarUnit()
*/
double mapUnitsPerScaleBarUnit() const { return mSettings.mapUnitsPerScaleBarUnit(); }
/**
* Sets the number of map \a units per scale bar unit used by the scalebar.
* \see mapUnitsPerScaleBarUnit()
*/
void setMapUnitsPerScaleBarUnit( double units ) { mSettings.setMapUnitsPerScaleBarUnit( units ); }
/**
* Returns the label for units.
* \see setUnitLabel()
*/
QString unitLabel() const { return mSettings.unitLabel(); }
/**
* Sets the \a label for units.
* \see unitLabel()
*/
void setUnitLabel( const QString &label ) { mSettings.setUnitLabel( label );}
/**
* Returns the font used for drawing text in the scalebar.
* \see setFont()
*/
QFont font() const;
/**
* Sets the \a font used for drawing text in the scalebar.
* \see setFont()
*/
void setFont( const QFont &font );
/**
* Returns the color used for drawing text in the scalebar.
* \see setFontColor()
* \see font()
*/
QColor fontColor() const { return mSettings.fontColor(); }
/**
* Sets the \a color used for drawing text in the scalebar.
* \see fontColor()
* \see setFont()
*/
void setFontColor( const QColor &color ) { mSettings.setFontColor( color ); }
/**
* Returns the color used for fills in the scalebar.
* \see setFillColor()
* \see fillColor2()
*/
QColor fillColor() const { return mSettings.fillColor(); }
/**
* Sets the \a color used for fills in the scalebar.
* \see fillColor()
* \see setFillColor2()
*/
void setFillColor( const QColor &color ) { mSettings.setFillColor( color ); }
/**
* Returns the secondary color used for fills in the scalebar.
* \see setFillColor2()
* \see fillColor()
*/
QColor fillColor2() const { return mSettings.fillColor2(); }
/**
* Sets the secondary \a color used for fills in the scalebar.
* \see fillColor2()
* \see setFillColor2()
*/
void setFillColor2( const QColor &color ) { mSettings.setFillColor2( color ); }
/**
* Returns the color used for lines in the scalebar.
* \see setLineColor()
*/
QColor lineColor() const { return mSettings.lineColor(); }
/**
* Sets the \a color used for lines in the scalebar.
* \see lineColor()
*/
void setLineColor( const QColor &color ) { mSettings.setLineColor( color ); }
/**
* Returns the line width in millimeters for lines in the scalebar.
* \see setLineWidth()
*/
double lineWidth() const { return mSettings.lineWidth(); }
/**
* Sets the line \a width in millimeters for lines in the scalebar.
* \see lineWidth()
*/
void setLineWidth( double width ) { mSettings.setLineWidth( width ); }
/**
* Returns the pen used for drawing outlines in the scalebar.
* \see setPen()
* \see brush()
*/
QPen pen() const { return mSettings.pen(); }
/**
* Returns the primary brush for the scalebar.
* \returns QBrush used for filling the scalebar
* \see setBrush
* \see brush2
* \see pen
*/
QBrush brush() const {return mSettings.brush();}
/**
* Returns the secondary brush for the scalebar. This is used for alternating color style scalebars, such
* as single and double box styles.
* \returns QBrush used for secondary color areas
* \see setBrush2
* \see brush
*/
QBrush brush2() const {return mSettings.brush2(); }
/**
* Returns the scalebar height (in millimeters).
* \see setHeight()
*/
double height() const { return mSettings.height(); }
/**
* Sets the scalebar \a height (in millimeters).
* \see height()
*/
void setHeight( double height ) { mSettings.setHeight( height ); }
/**
* Sets the \a map item linked to the scalebar.
* \see map()
*/
void setMap( QgsLayoutItemMap *map );
/**
* Returns the map item linked to the scalebar.
* \see setMap()
*/
QgsLayoutItemMap *map() const { return mMap; }
/**
* Returns the spacing (in millimeters) between labels and the scalebar.
* \see setLabelBarSpace()
*/
double labelBarSpace() const { return mSettings.labelBarSpace(); }
/**
* Sets the spacing (in millimeters) between labels and the scalebar.
* \see labelBarSpace()
*/
void setLabelBarSpace( double space ) {mSettings.setLabelBarSpace( space );}
/**
* Returns the spacing (margin) between the scalebar box and content in millimeters.
* \see setBoxContentSpace()
*/
double boxContentSpace() const { return mSettings.boxContentSpace(); }
/**
* Sets the \a space (margin) between the scalebar box and content in millimeters.
* \see boxContentSpace()
*/
void setBoxContentSpace( double space );
/**
* Returns the scalebar alignment.
* \see setAlignment()
*/
QgsScaleBarSettings::Alignment alignment() const { return mSettings.alignment(); }
/**
* Sets the scalebar \a alignment.
* \see alignment()
*/
void setAlignment( QgsScaleBarSettings::Alignment alignment );
/**
* Returns the distance units used by the scalebar.
* \see setUnits()
*/
QgsUnitTypes::DistanceUnit units() const { return mSettings.units(); }
/**
* Sets the distance \a units used by the scalebar.
* \see units()
*/
void setUnits( QgsUnitTypes::DistanceUnit units );
/**
* Returns the join style used for drawing lines in the scalebar.
* \see setLineJoinStyle()
*/
Qt::PenJoinStyle lineJoinStyle() const { return mSettings.lineJoinStyle(); }
/**
* Sets the join \a style used when drawing the lines in the scalebar
* \see lineJoinStyle()
*/
void setLineJoinStyle( Qt::PenJoinStyle style );
/**
* Returns the cap style used for drawing lines in the scalebar.
* \see setLineCapStyle()
*/
Qt::PenCapStyle lineCapStyle() const { return mSettings.lineCapStyle(); }
/**
* Sets the cap \a style used when drawing the lines in the scalebar.
* \see lineCapStyle()
*/
void setLineCapStyle( Qt::PenCapStyle style );
/**
* Applies the default scalebar settings to the scale bar.
* \see applyDefaultSize()
*/
void applyDefaultSettings();
/**
* Applies the default size to the scale bar (scale bar 1/5 of map item width)
* \see applyDefaultSettings()
*/
void applyDefaultSize( QgsUnitTypes::DistanceUnit units = QgsUnitTypes::DistanceMeters );
/**
* Sets the scale bar style by \a name.
*
* The \a name parameter gives the (untranslated) style name.
* Possibilities are: 'Single Box', 'Double Box', 'Line Ticks Middle',
* 'Line Ticks Down', 'Line Ticks Up', 'Numeric'
*
* \see style()
*/
void setStyle( const QString &name );
/**
* Returns the scale bar style name.
* \see setStyle()
*/
QString style() const;
/**
* Sets the scale bar box size to a size suitable for the scalebar content.
*/
void adjustBoxSize();
/**
* Adjusts the scale bar box size and updates the item.
*/
void update();
#if 0 //TODO
//overridden to apply minimum size
void setSceneRect( const QRectF &rectangle ) override;
#endif
void refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties ) override;
protected:
void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = nullptr ) override;
bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override;
bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context ) override;
private slots:
void updateSegmentSize();
//! Sets mCompositionMap to 0 if the map is deleted
void invalidateCurrentMap();
private:
//! Linked map
QgsLayoutItemMap *mMap = nullptr;
QgsScaleBarSettings mSettings;
//! Scalebar style
QgsScaleBarRenderer *mStyle = nullptr;
//! Width of a segment (in mm)
double mSegmentMillimeters;
//! Moves scalebar position to the left / right depending on alignment and change in item width
void correctXPositionAlignment( double width, double widthAfter );
//! Calculates with of a segment in mm and stores it in mSegmentMillimeters
void refreshSegmentMillimeters();
//! Returns diagonal of composer map in selected units (map units / meters / feet / nautical miles)
double mapWidth() const;
QgsScaleBarRenderer::ScaleBarContext createScaleContext() const;
};
#endif //QGSLAYOUTITEMSCALEBAR_H

View File

@ -138,7 +138,7 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even
// it's possible (in certain circumstances, e.g. when adding frame items) that this item
// has already been added to the layout
if ( item->layout() != layout() )
if ( item->scene() != layout() )
layout()->addLayoutItem( item );
layout()->setSelectedItem( item );