Skip to content

Commit a8b9723

Browse files
authored
[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
1 parent dc509f4 commit a8b9723

File tree

66 files changed

+96
-11
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+96
-11
lines changed

python/core/composer/qgscomposerlegend.sip

+12
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@ class QgsComposerLegend : QgsComposerItem
121121
void setStyleMargin( QgsLegendStyle::Style s, double margin );
122122
void setStyleMargin( QgsLegendStyle::Style s, QgsLegendStyle::Side side, double margin );
123123

124+
/** Returns the spacing in-between lines in mm
125+
* @note added in 3.0
126+
* @see setLineSpacing
127+
*/
128+
double lineSpacing() const;
129+
/** Sets the spacing in-between multiple lines
130+
* @param spacing Double value to use as spacing in between multiple lines
131+
* @note added in 3.0
132+
* @see lineSpacing
133+
*/
134+
void setLineSpacing( double spacing );
135+
124136
double boxSpace() const;
125137
void setBoxSpace( double s );
126138

src/app/composer/qgscomposerlegendwidget.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ void QgsComposerLegendWidget::setGuiElements()
144144
mIconLabelSpaceSpinBox->setValue( mLegend->style( QgsLegendStyle::SymbolLabel ).margin( QgsLegendStyle::Left ) );
145145
mBoxSpaceSpinBox->setValue( mLegend->boxSpace() );
146146
mColumnSpaceSpinBox->setValue( mLegend->columnSpace() );
147+
mLineSpacingSpinBox->setValue( mLegend->lineSpacing() );
147148

148149
mRasterBorderGroupBox->setChecked( mLegend->drawRasterBorder() );
149150
mRasterBorderWidthSpinBox->setValue( mLegend->rasterBorderWidth() );
@@ -450,6 +451,17 @@ void QgsComposerLegendWidget::on_mColumnSpaceSpinBox_valueChanged( double d )
450451
}
451452
}
452453

454+
void QgsComposerLegendWidget::on_mLineSpacingSpinBox_valueChanged( double d )
455+
{
456+
if ( mLegend )
457+
{
458+
mLegend->beginCommand( tr( "Legend line space" ), QgsComposerMergeCommand::LegendLineSpacing );
459+
mLegend->setLineSpacing( d );
460+
mLegend->adjustBoxSize();
461+
mLegend->update();
462+
mLegend->endCommand();
463+
}
464+
}
453465

454466
static void _moveLegendNode( QgsLayerTreeLayer* nodeLayer, int legendNodeIndex, int offset )
455467
{

src/app/composer/qgscomposerlegendwidget.h

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class QgsComposerLegendWidget: public QgsComposerItemBaseWidget, private Ui::Qgs
6666
void on_mFontColorButton_colorChanged( const QColor& newFontColor );
6767
void on_mBoxSpaceSpinBox_valueChanged( double d );
6868
void on_mColumnSpaceSpinBox_valueChanged( double d );
69+
void on_mLineSpacingSpinBox_valueChanged( double d );
6970
void on_mCheckBoxAutoUpdate_stateChanged( int state );
7071
void composerMapChanged( QgsComposerItem* item );
7172
void on_mCheckboxResizeContents_toggled( bool checked );

src/core/composer/qgscomposeritemcommand.h

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand
111111
LegendIconSymbolSpace,
112112
LegendBoxSpace,
113113
LegendColumnSpace,
114+
LegendLineSpacing,
114115
LegendRasterBorderWidth,
115116
LegendFontColor,
116117
LegendRasterBorderColor,

src/core/composer/qgscomposerlegend.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ void QgsComposerLegend::setStyleFont( QgsLegendStyle::Style s, const QFont& f )
288288
void QgsComposerLegend::setStyleMargin( QgsLegendStyle::Style s, double margin ) { rstyle( s ).setMargin( margin ); }
289289
void QgsComposerLegend::setStyleMargin( QgsLegendStyle::Style s, QgsLegendStyle::Side side, double margin ) { rstyle( s ).setMargin( side, margin ); }
290290

291+
double QgsComposerLegend::lineSpacing() const { return mSettings.lineSpacing(); }
292+
void QgsComposerLegend::setLineSpacing( double spacing ) { mSettings.setLineSpacing( spacing ); }
293+
291294
double QgsComposerLegend::boxSpace() const { return mSettings.boxSpace(); }
292295
void QgsComposerLegend::setBoxSpace( double s ) { mSettings.setBoxSpace( s ); }
293296

@@ -370,6 +373,7 @@ bool QgsComposerLegend::writeXml( QDomElement& elem, QDomDocument & doc ) const
370373

371374
composerLegendElem.setAttribute( QStringLiteral( "symbolWidth" ), QString::number( mSettings.symbolSize().width() ) );
372375
composerLegendElem.setAttribute( QStringLiteral( "symbolHeight" ), QString::number( mSettings.symbolSize().height() ) );
376+
composerLegendElem.setAttribute( QStringLiteral( "lineSpacing" ), QString::number( mSettings.lineSpacing() ) );
373377

374378
composerLegendElem.setAttribute( QStringLiteral( "rasterBorder" ), mSettings.drawRasterBorder() );
375379
composerLegendElem.setAttribute( QStringLiteral( "rasterBorderColor" ), QgsSymbolLayerUtils::encodeColor( mSettings.rasterBorderColor() ) );
@@ -501,6 +505,7 @@ bool QgsComposerLegend::readXml( const QDomElement& itemElem, const QDomDocument
501505

502506
mSettings.setSymbolSize( QSizeF( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble(), itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() ) );
503507
mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble(), itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() ) );
508+
mSettings.setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), "1.0" ).toDouble() );
504509

505510
mSettings.setDrawRasterBorder( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
506511
mSettings.setRasterBorderColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );

src/core/composer/qgscomposerlegend.h

+13
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,19 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem
149149
void setStyleMargin( QgsLegendStyle::Style s, double margin );
150150
void setStyleMargin( QgsLegendStyle::Style s, QgsLegendStyle::Side side, double margin );
151151

152+
/** Returns the spacing in-between lines in mm
153+
* @note added in 3.0
154+
* @see setLineSpacing
155+
*/
156+
double lineSpacing() const;
157+
158+
/** Sets the spacing in-between multiple lines
159+
* @param spacing Double value to use as spacing in between multiple lines
160+
* @note added in 3.0
161+
* @see lineSpacing
162+
*/
163+
void setLineSpacing( double spacing );
164+
152165
double boxSpace() const;
153166
void setBoxSpace( double s );
154167

src/core/layertree/qgslayertreemodellegendnode.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings& set
9393

9494
QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font();
9595
double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );
96+
double textDescent = settings.fontDescentMillimeters( symbolLabelFont );
9697

9798
QStringList lines = settings.splitStringForWrapping( data( Qt::DisplayRole ).toString() );
9899

99-
labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * settings.lineSpacing();
100+
labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * ( settings.lineSpacing() + textDescent );
100101

101102
double labelX = 0.0, labelY = 0.0;
102103
if ( ctx )
@@ -120,8 +121,8 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings& set
120121
if ( ctx )
121122
{
122123
settings.drawText( ctx->painter, labelX, labelY, *itemPart, symbolLabelFont );
123-
if ( itemPart != lines.end() )
124-
labelY += settings.lineSpacing() + textHeight;
124+
if ( itemPart != ( lines.end() - 1 ) )
125+
labelY += textDescent + settings.lineSpacing() + textHeight;
125126
}
126127
}
127128

src/core/qgslegendrenderer.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ QSizeF QgsLegendRenderer::drawTitle( QPainter* painter, QPointF point, Qt::Align
411411
size.rwidth() = qMax( width, size.rwidth() );
412412

413413
y += height;
414-
if ( titlePart != lines.end() )
414+
if ( titlePart != ( lines.end() - 1 ) )
415415
{
416416
y += mSettings.lineSpacing();
417417
}
@@ -537,7 +537,7 @@ QSizeF QgsLegendRenderer::drawLayerTitle( QgsLayerTreeLayer* nodeLayer, QPainter
537537
if ( painter ) mSettings.drawText( painter, point.x(), y, *layerItemPart, layerFont );
538538
qreal width = mSettings.textWidthMillimeters( layerFont, *layerItemPart );
539539
size.rwidth() = qMax( width, size.width() );
540-
if ( layerItemPart != lines.end() )
540+
if ( layerItemPart != ( lines.end() - 1 ) )
541541
{
542542
y += mSettings.lineSpacing();
543543
}
@@ -566,7 +566,7 @@ QSizeF QgsLegendRenderer::drawGroupTitle( QgsLayerTreeGroup* nodeGroup, QPainter
566566
if ( painter ) mSettings.drawText( painter, point.x(), y, *groupPart, groupFont );
567567
qreal width = mSettings.textWidthMillimeters( groupFont, *groupPart );
568568
size.rwidth() = qMax( width, size.width() );
569-
if ( groupPart != lines.end() )
569+
if ( groupPart != ( lines.end() - 1 ) )
570570
{
571571
y += mSettings.lineSpacing();
572572
}

src/core/qgslegendsettings.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ QgsLegendSettings::QgsLegendSettings()
2525
, mBoxSpace( 2 )
2626
, mSymbolSize( 7, 4 )
2727
, mWmsLegendSize( 50, 25 )
28-
, mLineSpacing( 1.5 )
28+
, mLineSpacing( 1 )
2929
, mColumnSpace( 2 )
3030
, mColumnCount( 1 )
3131
, mSplitLayer( false )
@@ -38,10 +38,10 @@ QgsLegendSettings::QgsLegendSettings()
3838
, mMapScale( 1 )
3939
, mDpi( 96 ) // based on QImage's default DPI
4040
{
41-
rstyle( QgsLegendStyle::Title ).setMargin( QgsLegendStyle::Bottom, 2 );
42-
rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Top, 2 );
43-
rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Top, 2 );
44-
rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Top, 2 );
41+
rstyle( QgsLegendStyle::Title ).setMargin( QgsLegendStyle::Bottom, 3.5 );
42+
rstyle( QgsLegendStyle::Group ).setMargin( QgsLegendStyle::Top, 3 );
43+
rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Top, 3 );
44+
rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Top, 2.5 );
4545
rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Top, 2 );
4646
rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Left, 2 );
4747
rstyle( QgsLegendStyle::Title ).rfont().setPointSizeF( 16.0 );

src/ui/composer/qgscomposerlegendwidgetbase.ui

+17
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,23 @@
965965
</property>
966966
</widget>
967967
</item>
968+
<item row="7" column="0">
969+
<widget class="QLabel" name="label_12">
970+
<property name="text">
971+
<string>Line space</string>
972+
</property>
973+
</widget>
974+
</item>
975+
<item row="7" column="1">
976+
<widget class="QgsDoubleSpinBox" name="mLineSpacingSpinBox">
977+
<property name="prefix">
978+
<string/>
979+
</property>
980+
<property name="suffix">
981+
<string> mm</string>
982+
</property>
983+
</widget>
984+
</item>
968985
<item row="0" column="0">
969986
<widget class="QLabel" name="label_10">
970987
<property name="toolTip">

tests/src/core/testqgslegendrenderer.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ class TestQgsLegendRenderer : public QObject
114114
void testBigMarker();
115115
void testMapUnits();
116116
void testTallSymbol();
117+
void testLineSpacing();
117118
void testLongSymbolText();
118119
void testThreeColumns();
119120
void testFilterByMap();
@@ -360,6 +361,28 @@ void TestQgsLegendRenderer::testTallSymbol()
360361
mVL2->setName( QStringLiteral( "Polygon Layer" ) );
361362
}
362363

364+
void TestQgsLegendRenderer::testLineSpacing()
365+
{
366+
QString testName = "legend_line_spacing";
367+
368+
QgsCategorizedSymbolRenderer* catRenderer = dynamic_cast<QgsCategorizedSymbolRenderer*>( mVL3->renderer() );
369+
QVERIFY( catRenderer );
370+
catRenderer->updateCategoryLabel( 1, "This is\nthree lines\nlong label" );
371+
372+
mVL2->setName( "This is a two lines\nlong label" );
373+
374+
QgsLayerTreeModel legendModel( mRoot );
375+
376+
QgsLegendSettings settings;
377+
settings.setWrapChar( "\n" );
378+
settings.setLineSpacing( 3 );
379+
_setStandardTestFont( settings );
380+
_renderLegend( testName, &legendModel, settings );
381+
QVERIFY( _verifyImage( testName, mReport ) );
382+
383+
mVL2->setName( "Polygon Layer" );
384+
}
385+
363386
void TestQgsLegendRenderer::testLongSymbolText()
364387
{
365388
QString testName = QStringLiteral( "legend_long_symbol_text" );

0 commit comments

Comments
 (0)