Skip to content

Commit

Permalink
[FEATURE] allow customization of line spacing for legend item labels (#…
Browse files Browse the repository at this point in the history
…3632)

* [FEATURE] allow customization of line spacing for legend item labels
* add test for legend line spacing and update control images
  • Loading branch information
nirvn committed Dec 13, 2016
1 parent dc509f4 commit a8b9723
Show file tree
Hide file tree
Showing 66 changed files with 96 additions and 11 deletions.
12 changes: 12 additions & 0 deletions python/core/composer/qgscomposerlegend.sip
Expand Up @@ -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 );

Expand Down
12 changes: 12 additions & 0 deletions src/app/composer/qgscomposerlegendwidget.cpp
Expand Up @@ -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() );
Expand Down Expand Up @@ -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 )
{
Expand Down
1 change: 1 addition & 0 deletions src/app/composer/qgscomposerlegendwidget.h
Expand Up @@ -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 );
Expand Down
1 change: 1 addition & 0 deletions src/core/composer/qgscomposeritemcommand.h
Expand Up @@ -111,6 +111,7 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand
LegendIconSymbolSpace,
LegendBoxSpace,
LegendColumnSpace,
LegendLineSpacing,
LegendRasterBorderWidth,
LegendFontColor,
LegendRasterBorderColor,
Expand Down
5 changes: 5 additions & 0 deletions src/core/composer/qgscomposerlegend.cpp
Expand Up @@ -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 ); }

Expand Down Expand Up @@ -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() ) );
Expand Down Expand Up @@ -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" ) ) ) );
Expand Down
13 changes: 13 additions & 0 deletions src/core/composer/qgscomposerlegend.h
Expand Up @@ -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 );

Expand Down
7 changes: 4 additions & 3 deletions src/core/layertree/qgslayertreemodellegendnode.cpp
Expand Up @@ -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 )
Expand All @@ -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;
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/core/qgslegendrenderer.cpp
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand Down
10 changes: 5 additions & 5 deletions src/core/qgslegendsettings.cpp
Expand Up @@ -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 )
Expand All @@ -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 );
Expand Down
17 changes: 17 additions & 0 deletions src/ui/composer/qgscomposerlegendwidgetbase.ui
Expand Up @@ -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">
Expand Down
23 changes: 23 additions & 0 deletions tests/src/core/testqgslegendrenderer.cpp
Expand Up @@ -114,6 +114,7 @@ class TestQgsLegendRenderer : public QObject
void testBigMarker();
void testMapUnits();
void testTallSymbol();
void testLineSpacing();
void testLongSymbolText();
void testThreeColumns();
void testFilterByMap();
Expand Down Expand Up @@ -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" );
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.

0 comments on commit a8b9723

Please sign in to comment.