Skip to content

Commit e08833a

Browse files
committed
Adv labeling, add multi-line spacing and alignment
1 parent a22742d commit e08833a

File tree

5 files changed

+77
-14
lines changed

5 files changed

+77
-14
lines changed

python/core/qgspallabeling.sip

+9
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ class QgsPalLayerSettings
3434
ShowAll // show upside down for all labels, including dynamic ones
3535
};
3636

37+
enum MultiLineAlign
38+
{
39+
MultiLeft = 0,
40+
MultiCenter,
41+
MultiRight
42+
};
43+
3744
// increment iterator in _writeDataDefinedPropertyMap() when adding more
3845
enum DataDefinedProperties
3946
{
@@ -118,6 +125,8 @@ class QgsPalLayerSettings
118125
bool labelOffsetInMapUnits; //true if label offset is in map units (otherwise in mm)
119126
bool distInMapUnits; //true if distance is in map units (otherwise in mm)
120127
QString wrapChar;
128+
double multilineHeight; //0.0 to 10.0, leading between lines as multiplyer of line height
129+
MultiLineAlign multilineAlign; // horizontal alignment of multi-line labels
121130
// called from register feature hook
122131
void calculateLabelSize( const QFontMetricsF* fm, QString text, double& labelX, double& labelY );
123132

src/app/qgslabelinggui.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
192192
}
193193

194194
wrapCharacterEdit->setText( lyr.wrapChar );
195+
mFontLineHeightSpinBox->setValue( lyr.multilineHeight );
196+
mFontMultiLineComboBox->setCurrentIndex(( unsigned int ) lyr.multilineAlign );
195197
chkPreserveRotation->setChecked( lyr.preserveRotation );
196198

197199
mPreviewBackgroundBtn->setColor( lyr.previewBkgrdColor );
@@ -461,6 +463,8 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
461463
lyr.minFeatureSize = mMinSizeSpinBox->value();
462464
lyr.fontSizeInMapUnits = ( mFontSizeUnitComboBox->currentIndex() == 1 );
463465
lyr.wrapChar = wrapCharacterEdit->text();
466+
lyr.multilineHeight = mFontLineHeightSpinBox->value();
467+
lyr.multilineAlign = ( QgsPalLayerSettings::MultiLineAlign ) mFontMultiLineComboBox->currentIndex();
464468
if ( chkPreserveRotation->isChecked() )
465469
{
466470
lyr.preserveRotation = true;

src/core/qgspallabeling.cpp

+50-9
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ QgsPalLayerSettings::QgsPalLayerSettings()
187187
labelOffsetInMapUnits = true;
188188
distInMapUnits = false;
189189
wrapChar = "";
190+
multilineHeight = 1.0;
191+
multilineAlign = MultiLeft;
190192
preserveRotation = true;
191193
}
192194

@@ -235,6 +237,8 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
235237
distInMapUnits = s.distInMapUnits;
236238
labelOffsetInMapUnits = s.labelOffsetInMapUnits;
237239
wrapChar = s.wrapChar;
240+
multilineHeight = s.multilineHeight;
241+
multilineAlign = s.multilineAlign;
238242
preserveRotation = s.preserveRotation;
239243

240244
dataDefinedProperties = s.dataDefinedProperties;
@@ -416,6 +420,8 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
416420
distInMapUnits = layer->customProperty( "labeling/distInMapUnits" ).toBool();
417421
labelOffsetInMapUnits = layer->customProperty( "labeling/labelOffsetInMapUnits", QVariant( true ) ).toBool();
418422
wrapChar = layer->customProperty( "labeling/wrapChar" ).toString();
423+
multilineHeight = layer->customProperty( "labeling/multilineHeight", QVariant( 1.0 ) ).toDouble();
424+
multilineAlign = ( MultiLineAlign ) layer->customProperty( "labeling/multilineAlign", QVariant( MultiLeft ) ).toUInt();
419425
preserveRotation = layer->customProperty( "labeling/preserveRotation", QVariant( true ) ).toBool();
420426
_readDataDefinedPropertyMap( layer, dataDefinedProperties );
421427
}
@@ -475,6 +481,8 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
475481
layer->setCustomProperty( "labeling/distInMapUnits", distInMapUnits );
476482
layer->setCustomProperty( "labeling/labelOffsetInMapUnits", labelOffsetInMapUnits );
477483
layer->setCustomProperty( "labeling/wrapChar", wrapChar );
484+
layer->setCustomProperty( "labeling/multilineHeight", multilineHeight );
485+
layer->setCustomProperty( "labeling/multilineAlign", ( unsigned int )multilineAlign );
478486
layer->setCustomProperty( "labeling/preserveRotation", preserveRotation );
479487
_writeDataDefinedPropertyMap( layer, dataDefinedProperties );
480488
}
@@ -540,16 +548,20 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF* fm, QString t
540548
text.append( ">" );
541549
}
542550

543-
double w, h;
551+
double w = 0.0, h = 0.0;
544552
QStringList multiLineSplit;
545553
if ( !wrapChar.isEmpty() )
546554
multiLineSplit = text.split( wrapChar );
547555
else
548556
multiLineSplit = text.split( "\n" );
557+
int lines = multiLineSplit.size();
549558

550-
h = fm->height() * multiLineSplit.size() / rasterCompressFactor;
551-
w = 0;
552-
for ( int i = 0; i < multiLineSplit.size(); ++i )
559+
double labelHeight = fm->ascent() + fm->descent(); // ignore +1 for baseline
560+
561+
h += fm->height() + ( double )(( lines - 1 ) * labelHeight * multilineHeight );
562+
h /= rasterCompressFactor;
563+
564+
for ( int i = 0; i < lines; ++i )
553565
{
554566
double width = fm->width( multiLineSplit.at( i ) );
555567
if ( width > w )
@@ -1661,7 +1673,24 @@ void QgsPalLabeling::drawLabel( pal::LabelPosition* label, QPainter* painter, co
16611673
else
16621674
multiLineList = txt.split( "\n" );
16631675

1664-
for ( int i = 0; i < multiLineList.size(); ++i )
1676+
int lines = multiLineList.size();
1677+
1678+
double labelWidest = 0.0;
1679+
for ( int i = 0; i < lines; ++i )
1680+
{
1681+
double labelWidth = labelfm->width( multiLineList.at( i ) );
1682+
if ( labelWidth > labelWidest )
1683+
{
1684+
labelWidest = labelWidth;
1685+
}
1686+
}
1687+
1688+
double labelHeight = labelfm->ascent() + labelfm->descent(); // ignore +1 for baseline
1689+
1690+
// needed to move bottom of text's descender to within bottom edge of label
1691+
double ascentOffset = 0.25 * labelfm->ascent(); // labelfm->descent() is not enough
1692+
1693+
for ( int i = 0; i < lines; ++i )
16651694
{
16661695
painter->save();
16671696
painter->translate( QPointF( outPt.x(), outPt.y() ) );
@@ -1671,10 +1700,22 @@ void QgsPalLabeling::drawLabel( pal::LabelPosition* label, QPainter* painter, co
16711700
// to workaround a Qt font scaling bug with small font sizes
16721701
painter->scale( 1.0 / lyr.rasterCompressFactor, 1.0 / lyr.rasterCompressFactor );
16731702

1674-
double yMultiLineOffset = ( multiLineList.size() - 1 - i ) * labelfm->height();
1675-
double ascentOffset = 0.0;
1676-
ascentOffset = labelfm->height() * 0.25 * labelfm->ascent() / labelfm->height();
1677-
painter->translate( QPointF( 0, - ascentOffset - yMultiLineOffset ) );
1703+
// figure x offset for horizontal alignment of multiple lines
1704+
double xMultiLineOffset = 0.0;
1705+
if ( lines > 1 && lyr.multilineAlign != QgsPalLayerSettings::MultiLeft )
1706+
{
1707+
double labelWidth = labelfm->width( multiLineList.at( i ) );
1708+
double labelWidthDiff = labelWidest - labelWidth;
1709+
if ( lyr.multilineAlign == QgsPalLayerSettings::MultiCenter )
1710+
{
1711+
labelWidthDiff /= 2;
1712+
}
1713+
xMultiLineOffset = labelWidthDiff * lyr.rasterCompressFactor;
1714+
QgsDebugMsg( QString( "xMultiLineOffset: %0" ).arg( xMultiLineOffset ) );
1715+
}
1716+
1717+
double yMultiLineOffset = ( lines - 1 - i ) * labelHeight * lyr.multilineHeight;
1718+
painter->translate( QPointF( xMultiLineOffset, - ascentOffset - yMultiLineOffset ) );
16781719

16791720
if ( drawBuffer )
16801721
{

src/core/qgspallabeling.h

+9
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ class CORE_EXPORT QgsPalLayerSettings
8888
ShowAll // show upside down for all labels, including dynamic ones
8989
};
9090

91+
enum MultiLineAlign
92+
{
93+
MultiLeft = 0,
94+
MultiCenter,
95+
MultiRight
96+
};
97+
9198
// increment iterator in _writeDataDefinedPropertyMap() when adding more
9299
enum DataDefinedProperties
93100
{
@@ -172,6 +179,8 @@ class CORE_EXPORT QgsPalLayerSettings
172179
bool labelOffsetInMapUnits; //true if label offset is in map units (otherwise in mm)
173180
bool distInMapUnits; //true if distance is in map units (otherwise in mm)
174181
QString wrapChar;
182+
double multilineHeight; //0.0 to 10.0, leading between lines as multiplyer of line height
183+
MultiLineAlign multilineAlign; // horizontal alignment of multi-line labels
175184
// called from register feature hook
176185
void calculateLabelSize( const QFontMetricsF* fm, QString text, double& labelX, double& labelY );
177186

src/ui/qgslabelingguibase.ui

+5-5
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@
449449
<property name="geometry">
450450
<rect>
451451
<x>0</x>
452-
<y>0</y>
452+
<y>-162</y>
453453
<width>686</width>
454454
<height>628</height>
455455
</rect>
@@ -523,7 +523,7 @@
523523
<item>
524524
<widget class="QDoubleSpinBox" name="mFontLineHeightSpinBox">
525525
<property name="enabled">
526-
<bool>false</bool>
526+
<bool>true</bool>
527527
</property>
528528
<property name="sizePolicy">
529529
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -576,7 +576,7 @@
576576
<item>
577577
<widget class="QComboBox" name="mFontMultiLineComboBox">
578578
<property name="enabled">
579-
<bool>false</bool>
579+
<bool>true</bool>
580580
</property>
581581
<property name="sizePolicy">
582582
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -1493,7 +1493,7 @@
14931493
<rect>
14941494
<x>0</x>
14951495
<y>0</y>
1496-
<width>686</width>
1496+
<width>636</width>
14971497
<height>553</height>
14981498
</rect>
14991499
</property>
@@ -2355,7 +2355,7 @@
23552355
<rect>
23562356
<x>0</x>
23572357
<y>0</y>
2358-
<width>686</width>
2358+
<width>488</width>
23592359
<height>951</height>
23602360
</rect>
23612361
</property>

0 commit comments

Comments
 (0)