[FEATURE] allow customization of line spacing for legend item labels (#3632)
* [FEATURE] allow customization of line spacing for legend item labels * add test for legend line spacing and update control images
@ -121,6 +121,18 @@ class QgsComposerLegend : QgsComposerItem
|
||||
void setStyleMargin( QgsLegendStyle::Style s, double margin );
|
||||
void setStyleMargin( QgsLegendStyle::Style s, QgsLegendStyle::Side side, double margin );
|
||||
|
||||
/** Returns the spacing in-between lines in mm
|
||||
* @note added in 3.0
|
||||
* @see setLineSpacing
|
||||
*/
|
||||
double lineSpacing() const;
|
||||
/** Sets the spacing in-between multiple lines
|
||||
* @param spacing Double value to use as spacing in between multiple lines
|
||||
* @note added in 3.0
|
||||
* @see lineSpacing
|
||||
*/
|
||||
void setLineSpacing( double spacing );
|
||||
|
||||
double boxSpace() const;
|
||||
void setBoxSpace( double s );
|
||||
|
||||
|
@ -144,6 +144,7 @@ void QgsComposerLegendWidget::setGuiElements()
|
||||
mIconLabelSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::SymbolLabel ).margin( QgsLegendStyle::Left ) );
|
||||
mBoxSpaceSpinBox->setValue( mLegend->boxSpace() );
|
||||
mColumnSpaceSpinBox->setValue( mLegend->columnSpace() );
|
||||
mLineSpacingSpinBox->setValue( mLegend->lineSpacing() );
|
||||
|
||||
mRasterBorderGroupBox->setChecked( mLegend->drawRasterBorder() );
|
||||
mRasterBorderWidthSpinBox->setValue( mLegend->rasterBorderWidth() );
|
||||
@ -450,6 +451,17 @@ void QgsComposerLegendWidget::on_mColumnSpaceSpinBox_valueChanged( double d )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsComposerLegendWidget::on_mLineSpacingSpinBox_valueChanged( double d )
|
||||
{
|
||||
if ( mLegend )
|
||||
{
|
||||
mLegend->beginCommand( tr( "Legend line space" ), QgsComposerMergeCommand::LegendLineSpacing );
|
||||
mLegend->setLineSpacing( d );
|
||||
mLegend->adjustBoxSize();
|
||||
mLegend->update();
|
||||
mLegend->endCommand();
|
||||
}
|
||||
}
|
||||
|
||||
static void _moveLegendNode( QgsLayerTreeLayer* nodeLayer, int legendNodeIndex, int offset )
|
||||
{
|
||||
|
@ -66,6 +66,7 @@ class QgsComposerLegendWidget: public QgsComposerItemBaseWidget, private Ui::Qgs
|
||||
void on_mFontColorButton_colorChanged( const QColor& newFontColor );
|
||||
void on_mBoxSpaceSpinBox_valueChanged( double d );
|
||||
void on_mColumnSpaceSpinBox_valueChanged( double d );
|
||||
void on_mLineSpacingSpinBox_valueChanged( double d );
|
||||
void on_mCheckBoxAutoUpdate_stateChanged( int state );
|
||||
void composerMapChanged( QgsComposerItem* item );
|
||||
void on_mCheckboxResizeContents_toggled( bool checked );
|
||||
|
@ -111,6 +111,7 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand
|
||||
LegendIconSymbolSpace,
|
||||
LegendBoxSpace,
|
||||
LegendColumnSpace,
|
||||
LegendLineSpacing,
|
||||
LegendRasterBorderWidth,
|
||||
LegendFontColor,
|
||||
LegendRasterBorderColor,
|
||||
|
@ -288,6 +288,9 @@ void QgsComposerLegend::setStyleFont( QgsLegendStyle::Style s, const QFont& f )
|
||||
void QgsComposerLegend::setStyleMargin( QgsLegendStyle::Style s, double margin ) { rstyle( s ).setMargin( margin ); }
|
||||
void QgsComposerLegend::setStyleMargin( QgsLegendStyle::Style s, QgsLegendStyle::Side side, double margin ) { rstyle( s ).setMargin( side, margin ); }
|
||||
|
||||
double QgsComposerLegend::lineSpacing() const { return mSettings.lineSpacing(); }
|
||||
void QgsComposerLegend::setLineSpacing( double spacing ) { mSettings.setLineSpacing( spacing ); }
|
||||
|
||||
double QgsComposerLegend::boxSpace() const { return mSettings.boxSpace(); }
|
||||
void QgsComposerLegend::setBoxSpace( double s ) { mSettings.setBoxSpace( s ); }
|
||||
|
||||
@ -370,6 +373,7 @@ bool QgsComposerLegend::writeXml( QDomElement& elem, QDomDocument & doc ) const
|
||||
|
||||
composerLegendElem.setAttribute( QStringLiteral( "symbolWidth" ), QString::number( mSettings.symbolSize().width() ) );
|
||||
composerLegendElem.setAttribute( QStringLiteral( "symbolHeight" ), QString::number( mSettings.symbolSize().height() ) );
|
||||
composerLegendElem.setAttribute( QStringLiteral( "lineSpacing" ), QString::number( mSettings.lineSpacing() ) );
|
||||
|
||||
composerLegendElem.setAttribute( QStringLiteral( "rasterBorder" ), mSettings.drawRasterBorder() );
|
||||
composerLegendElem.setAttribute( QStringLiteral( "rasterBorderColor" ), QgsSymbolLayerUtils::encodeColor( mSettings.rasterBorderColor() ) );
|
||||
@ -501,6 +505,7 @@ bool QgsComposerLegend::readXml( const QDomElement& itemElem, const QDomDocument
|
||||
|
||||
mSettings.setSymbolSize( QSizeF( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble(), itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() ) );
|
||||
mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble(), itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() ) );
|
||||
mSettings.setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), "1.0" ).toDouble() );
|
||||
|
||||
mSettings.setDrawRasterBorder( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
|
||||
mSettings.setRasterBorderColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );
|
||||
|
@ -149,6 +149,19 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem
|
||||
void setStyleMargin( QgsLegendStyle::Style s, double margin );
|
||||
void setStyleMargin( QgsLegendStyle::Style s, QgsLegendStyle::Side side, double margin );
|
||||
|
||||
/** Returns the spacing in-between lines in mm
|
||||
* @note added in 3.0
|
||||
* @see setLineSpacing
|
||||
*/
|
||||
double lineSpacing() const;
|
||||
|
||||
/** Sets the spacing in-between multiple lines
|
||||
* @param spacing Double value to use as spacing in between multiple lines
|
||||
* @note added in 3.0
|
||||
* @see lineSpacing
|
||||
*/
|
||||
void setLineSpacing( double spacing );
|
||||
|
||||
double boxSpace() const;
|
||||
void setBoxSpace( double s );
|
||||
|
||||
|
@ -93,10 +93,11 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings& set
|
||||
|
||||
QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font();
|
||||
double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );
|
||||
double textDescent = settings.fontDescentMillimeters( symbolLabelFont );
|
||||
|
||||
QStringList lines = settings.splitStringForWrapping( data( Qt::DisplayRole ).toString() );
|
||||
|
||||
labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * settings.lineSpacing();
|
||||
labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * ( settings.lineSpacing() + textDescent );
|
||||
|
||||
double labelX = 0.0, labelY = 0.0;
|
||||
if ( ctx )
|
||||
@ -120,8 +121,8 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings& set
|
||||
if ( ctx )
|
||||
{
|
||||
settings.drawText( ctx->painter, labelX, labelY, *itemPart, symbolLabelFont );
|
||||
if ( itemPart != lines.end() )
|
||||
labelY += settings.lineSpacing() + textHeight;
|
||||
if ( itemPart != ( lines.end() - 1 ) )
|
||||
labelY += textDescent + settings.lineSpacing() + textHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,7 +411,7 @@ QSizeF QgsLegendRenderer::drawTitle( QPainter* painter, QPointF point, Qt::Align
|
||||
size.rwidth() = qMax( width, size.rwidth() );
|
||||
|
||||
y += height;
|
||||
if ( titlePart != lines.end() )
|
||||
if ( titlePart != ( lines.end() - 1 ) )
|
||||
{
|
||||
y += mSettings.lineSpacing();
|
||||
}
|
||||
@ -537,7 +537,7 @@ QSizeF QgsLegendRenderer::drawLayerTitle( QgsLayerTreeLayer* nodeLayer, QPainter
|
||||
if ( painter ) mSettings.drawText( painter, point.x(), y, *layerItemPart, layerFont );
|
||||
qreal width = mSettings.textWidthMillimeters( layerFont, *layerItemPart );
|
||||
size.rwidth() = qMax( width, size.width() );
|
||||
if ( layerItemPart != lines.end() )
|
||||
if ( layerItemPart != ( lines.end() - 1 ) )
|
||||
{
|
||||
y += mSettings.lineSpacing();
|
||||
}
|
||||
@ -566,7 +566,7 @@ QSizeF QgsLegendRenderer::drawGroupTitle( QgsLayerTreeGroup* nodeGroup, QPainter
|
||||
if ( painter ) mSettings.drawText( painter, point.x(), y, *groupPart, groupFont );
|
||||
qreal width = mSettings.textWidthMillimeters( groupFont, *groupPart );
|
||||
size.rwidth() = qMax( width, size.width() );
|
||||
if ( groupPart != lines.end() )
|
||||
if ( groupPart != ( lines.end() - 1 ) )
|
||||
{
|
||||
y += mSettings.lineSpacing();
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ QgsLegendSettings::QgsLegendSettings()
|
||||
, mBoxSpace( 2 )
|
||||
, mSymbolSize( 7, 4 )
|
||||
, mWmsLegendSize( 50, 25 )
|
||||
, mLineSpacing( 1.5 )
|
||||
, mLineSpacing( 1 )
|
||||
, mColumnSpace( 2 )
|
||||
, mColumnCount( 1 )
|
||||
, mSplitLayer( false )
|
||||
@ -38,10 +38,10 @@ QgsLegendSettings::QgsLegendSettings()
|
||||
, mMapScale( 1 )
|
||||
, mDpi( 96 ) // based on QImage's default DPI
|
||||
{
|
||||
rstyle( QgsLegendStyle::Title ).setMargin( QgsLegendStyle::Bottom, 2 );
|
||||
rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Top, 2 );
|
||||
rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Top, 2 );
|
||||
rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Top, 2 );
|
||||
rstyle( QgsLegendStyle::Title ).setMargin( QgsLegendStyle::Bottom, 3.5 );
|
||||
rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Top, 3 );
|
||||
rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Top, 3 );
|
||||
rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Top, 2.5 );
|
||||
rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Top, 2 );
|
||||
rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Left, 2 );
|
||||
rstyle( QgsLegendStyle::Title ).rfont().setPointSizeF( 16.0 );
|
||||
|
@ -965,6 +965,23 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Line space</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="mLineSpacingSpinBox">
|
||||
<property name="prefix">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="toolTip">
|
||||
|
@ -114,6 +114,7 @@ class TestQgsLegendRenderer : public QObject
|
||||
void testBigMarker();
|
||||
void testMapUnits();
|
||||
void testTallSymbol();
|
||||
void testLineSpacing();
|
||||
void testLongSymbolText();
|
||||
void testThreeColumns();
|
||||
void testFilterByMap();
|
||||
@ -360,6 +361,28 @@ void TestQgsLegendRenderer::testTallSymbol()
|
||||
mVL2->setName( QStringLiteral( "Polygon Layer" ) );
|
||||
}
|
||||
|
||||
void TestQgsLegendRenderer::testLineSpacing()
|
||||
{
|
||||
QString testName = "legend_line_spacing";
|
||||
|
||||
QgsCategorizedSymbolRenderer* catRenderer = dynamic_cast<QgsCategorizedSymbolRenderer*>( mVL3->renderer() );
|
||||
QVERIFY( catRenderer );
|
||||
catRenderer->updateCategoryLabel( 1, "This is\nthree lines\nlong label" );
|
||||
|
||||
mVL2->setName( "This is a two lines\nlong label" );
|
||||
|
||||
QgsLayerTreeModel legendModel( mRoot );
|
||||
|
||||
QgsLegendSettings settings;
|
||||
settings.setWrapChar( "\n" );
|
||||
settings.setLineSpacing( 3 );
|
||||
_setStandardTestFont( settings );
|
||||
_renderLegend( testName, &legendModel, settings );
|
||||
QVERIFY( _verifyImage( testName, mReport ) );
|
||||
|
||||
mVL2->setName( "Polygon Layer" );
|
||||
}
|
||||
|
||||
void TestQgsLegendRenderer::testLongSymbolText()
|
||||
{
|
||||
QString testName = QStringLiteral( "legend_long_symbol_text" );
|
||||
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 6.4 KiB |
BIN
tests/testdata/control_images/legend/expected_legend_line_spacing/expected_legend_line_spacing.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 828 B |
Before Width: | Height: | Size: 625 B After Width: | Height: | Size: 604 B |
Before Width: | Height: | Size: 625 B After Width: | Height: | Size: 604 B |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 806 B After Width: | Height: | Size: 816 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 987 B After Width: | Height: | Size: 984 B |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 353 B After Width: | Height: | Size: 360 B |
Before Width: | Height: | Size: 166 B |