Skip to content

Commit

Permalink
Add custom line direction symbols to labeling
Browse files Browse the repository at this point in the history
- Options to place symbol above or below label text
- Option to reverse symbol direction
- Add character selector dialog for single font to src/gui
  • Loading branch information
dakcarto committed Nov 11, 2012
1 parent badeeae commit bb947b4
Show file tree
Hide file tree
Showing 12 changed files with 639 additions and 54 deletions.
14 changes: 13 additions & 1 deletion python/core/qgspallabeling.sip
Expand Up @@ -34,6 +34,13 @@ class QgsPalLayerSettings
ShowAll // show upside down for all labels, including dynamic ones
};

enum DirectionSymbols
{
SymbolLeftRight, // place direction symbols on left/right of label
SymbolAbove, // place direction symbols on above label
SymbolBelow // place direction symbols on below label
};

enum MultiLineAlign
{
MultiLeft = 0,
Expand Down Expand Up @@ -117,9 +124,14 @@ class QgsPalLayerSettings
bool displayAll; // if true, all features will be labelled even though overlaps occur
bool mergeLines;
double minFeatureSize; // minimum feature size to be labelled (in mm)
// Adds '<' or '>' to the label string pointing to the direction of the line / polygon ring
// Adds '<' or '>', or user-defined symbol to the label string pointing to the
// direction of the line / polygon ring
// Works only if Placement == Line
bool addDirectionSymbol;
QString leftDirectionSymbol;
QString rightDirectionSymbol;
bool reverseDirectionSymbol;
DirectionSymbols placeDirectionSymbol; // whether to place left/right, above or below label
unsigned int upsidedownLabels; // whether, or how, to show upsidedown labels
bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
bool fontLimitPixelSize; // true is label should be limited by fontMinPixelSize/fontMaxPixelSize
Expand Down
72 changes: 66 additions & 6 deletions src/app/qgslabelinggui.cpp
Expand Up @@ -26,6 +26,7 @@
#include "qgsexpressionbuilderdialog.h"
#include "qgsexpression.h"
#include "qgsmapcanvas.h"
#include "qgscharacterselectdialog.h"

#include <QColorDialog>
#include <QFontDialog>
Expand All @@ -41,6 +42,7 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
if ( !layer ) return;

setupUi( this );
mCharDlg = new QgsCharacterSelectorDialog( this );

mRefFont = lblFontPreview->font();
mPreviewSize = 24;
Expand Down Expand Up @@ -77,7 +79,7 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM

//mTabWidget->setEnabled( chkEnableLabeling->isChecked() );
chkMergeLines->setEnabled( layer->geometryType() == QGis::Line );
chkAddDirectionSymbol->setEnabled( layer->geometryType() == QGis::Line );
mDirectSymbGroupBox->setEnabled( layer->geometryType() == QGis::Line );
label_19->setEnabled( layer->geometryType() != QGis::Point );
mMinSizeSpinBox->setEnabled( layer->geometryType() != QGis::Point );

Expand Down Expand Up @@ -172,7 +174,25 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
mPalShowAllLabelsForLayerChkBx->setChecked( lyr.displayAll );
chkMergeLines->setChecked( lyr.mergeLines );
mMinSizeSpinBox->setValue( lyr.minFeatureSize );
chkAddDirectionSymbol->setChecked( lyr.addDirectionSymbol );
mDirectSymbGroupBox->setChecked( lyr.addDirectionSymbol );
mDirectSymbLeftLineEdit->setText( lyr.leftDirectionSymbol );
mDirectSymbRightLineEdit->setText( lyr.rightDirectionSymbol );
mDirectSymbRevChkBx->setChecked( lyr.reverseDirectionSymbol );
switch ( lyr.placeDirectionSymbol )
{
case QgsPalLayerSettings::SymbolLeftRight:
mDirectSymbRadioBtnLR->setChecked( true );
break;
case QgsPalLayerSettings::SymbolAbove:
mDirectSymbRadioBtnAbove->setChecked( true );
break;
case QgsPalLayerSettings::SymbolBelow:
mDirectSymbRadioBtnBelow->setChecked( true );
break;
default:
mDirectSymbRadioBtnLR->setChecked( true );
break;
}

// upside-down labels
switch ( lyr.upsidedownLabels )
Expand Down Expand Up @@ -449,14 +469,24 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
lyr.decimals = spinDecimals->value();
lyr.plusSign = true;
}
if ( chkAddDirectionSymbol->isChecked() )

lyr.addDirectionSymbol = mDirectSymbGroupBox->isChecked();
lyr.leftDirectionSymbol = mDirectSymbLeftLineEdit->text();
lyr.rightDirectionSymbol = mDirectSymbRightLineEdit->text();
lyr.reverseDirectionSymbol = mDirectSymbRevChkBx->isChecked();
if ( mDirectSymbRadioBtnLR->isChecked() )
{
lyr.addDirectionSymbol = true;
lyr.placeDirectionSymbol = QgsPalLayerSettings::SymbolLeftRight;
}
else
else if ( mDirectSymbRadioBtnAbove->isChecked() )
{
lyr.placeDirectionSymbol = QgsPalLayerSettings::SymbolAbove;
}
else if ( mDirectSymbRadioBtnBelow->isChecked() )
{
lyr.addDirectionSymbol = false;
lyr.placeDirectionSymbol = QgsPalLayerSettings::SymbolBelow;
}

if ( mUpsidedownRadioOff->isChecked() )
{
lyr.upsidedownLabels = QgsPalLayerSettings::Upright;
Expand Down Expand Up @@ -736,6 +766,8 @@ void QgsLabelingGui::updateFont( QFont font )
}

lblFontName->setText( QString( "%1%2" ).arg( mRefFont.family() ).arg( missingtxt ) );
mDirectSymbLeftLineEdit->setFont( mRefFont );
mDirectSymbRightLineEdit->setFont( mRefFont );

blockFontChangeSignals( true );
populateFontStyleComboBox();
Expand Down Expand Up @@ -1101,6 +1133,34 @@ void QgsLabelingGui::on_mPreviewBackgroundBtn_clicked()
setPreviewBackground( color );
}

void QgsLabelingGui::on_mDirectSymbLeftToolBtn_clicked()
{
bool gotChar = false;
QChar dirSymb = QChar();

dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ) );

if ( !gotChar )
return;

if ( !dirSymb.isNull() )
mDirectSymbLeftLineEdit->setText( QString( dirSymb ) );
}

void QgsLabelingGui::on_mDirectSymbRightToolBtn_clicked()
{
bool gotChar = false;
QChar dirSymb = QChar();

dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ) );

if ( !gotChar )
return;

if ( !dirSymb.isNull() )
mDirectSymbRightLineEdit->setText( QString( dirSymb ) );
}

void QgsLabelingGui::disableDataDefinedAlignment()
{
mHorizontalAlignmentComboBox->setCurrentIndex( mHorizontalAlignmentComboBox->findText( "" ) );
Expand Down
4 changes: 4 additions & 0 deletions src/app/qgslabelinggui.h
Expand Up @@ -24,6 +24,7 @@

class QgsVectorLayer;
class QgsMapCanvas;
class QgsCharacterSelectorDialog;

#include "qgspallabeling.h"

Expand Down Expand Up @@ -70,6 +71,8 @@ class QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
void on_mPreviewTextEdit_textChanged( const QString & text );
void on_mPreviewTextBtn_clicked();
void on_mPreviewBackgroundBtn_clicked();
void on_mDirectSymbLeftToolBtn_clicked();
void on_mDirectSymbRightToolBtn_clicked();

protected:
void blockFontChangeSignals( bool blk );
Expand All @@ -90,6 +93,7 @@ class QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
QgsVectorLayer* mLayer;
QgsMapCanvas* mMapCanvas;
QFontDatabase mFontDB;
QgsCharacterSelectorDialog* mCharDlg;

// background reference font
QFont mRefFont;
Expand Down
90 changes: 74 additions & 16 deletions src/core/qgspallabeling.cpp
Expand Up @@ -213,6 +213,10 @@ QgsPalLayerSettings::QgsPalLayerSettings()
vectorScaleFactor = 1.0;
rasterCompressFactor = 1.0;
addDirectionSymbol = false;
leftDirectionSymbol = QString( "<" );
rightDirectionSymbol = QString( ">" );
reverseDirectionSymbol = false;
placeDirectionSymbol = SymbolLeftRight;
upsidedownLabels = Upright;
fontSizeInMapUnits = false;
fontLimitPixelSize = false;
Expand Down Expand Up @@ -266,6 +270,10 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
vectorScaleFactor = s.vectorScaleFactor;
rasterCompressFactor = s.rasterCompressFactor;
addDirectionSymbol = s.addDirectionSymbol;
leftDirectionSymbol = s.leftDirectionSymbol;
rightDirectionSymbol = s.rightDirectionSymbol;
reverseDirectionSymbol = s.reverseDirectionSymbol;
placeDirectionSymbol = s.placeDirectionSymbol;
upsidedownLabels = s.upsidedownLabels;
fontSizeInMapUnits = s.fontSizeInMapUnits;
fontLimitPixelSize = s.fontLimitPixelSize;
Expand Down Expand Up @@ -433,7 +441,7 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
textFont.setWordSpacing( layer->customProperty( "labeling/fontWordSpacing", QVariant( 0.0 ) ).toDouble() );
textColor = _readColor( layer, "labeling/textColor" );
textTransp = layer->customProperty( "labeling/textTransp" ).toInt();
previewBkgrdColor = QColor( layer->customProperty( "labeling/previewBkgrdColor", "#ffffff" ).toString() );
previewBkgrdColor = QColor( layer->customProperty( "labeling/previewBkgrdColor", QVariant( "#ffffff" ) ).toString() );
enabled = layer->customProperty( "labeling/enabled" ).toBool();
priority = layer->customProperty( "labeling/priority" ).toInt();
obstacle = layer->customProperty( "labeling/obstacle" ).toBool();
Expand All @@ -452,6 +460,10 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
displayAll = layer->customProperty( "labeling/displayAll", QVariant( false ) ).toBool();
mergeLines = layer->customProperty( "labeling/mergeLines" ).toBool();
addDirectionSymbol = layer->customProperty( "labeling/addDirectionSymbol" ).toBool();
leftDirectionSymbol = layer->customProperty( "labeling/leftDirectionSymbol", QVariant( "<" ) ).toString();
rightDirectionSymbol = layer->customProperty( "labeling/rightDirectionSymbol", QVariant( ">" ) ).toString();
reverseDirectionSymbol = layer->customProperty( "labeling/reverseDirectionSymbol" ).toBool();
placeDirectionSymbol = ( DirectionSymbols ) layer->customProperty( "labeling/placeDirectionSymbol", QVariant( SymbolLeftRight ) ).toUInt();
upsidedownLabels = ( UpsideDownLabels ) layer->customProperty( "labeling/upsidedownLabels", QVariant( Upright ) ).toUInt();
minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble();
fontSizeInMapUnits = layer->customProperty( "labeling/fontSizeInMapUnits" ).toBool();
Expand Down Expand Up @@ -516,6 +528,10 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
layer->setCustomProperty( "labeling/displayAll", displayAll );
layer->setCustomProperty( "labeling/mergeLines", mergeLines );
layer->setCustomProperty( "labeling/addDirectionSymbol", addDirectionSymbol );
layer->setCustomProperty( "labeling/leftDirectionSymbol", leftDirectionSymbol );
layer->setCustomProperty( "labeling/rightDirectionSymbol", rightDirectionSymbol );
layer->setCustomProperty( "labeling/reverseDirectionSymbol", reverseDirectionSymbol );
layer->setCustomProperty( "labeling/placeDirectionSymbol", ( unsigned int )placeDirectionSymbol );
layer->setCustomProperty( "labeling/upsidedownLabels", ( unsigned int )upsidedownLabels );
layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize );
layer->setCustomProperty( "labeling/fontSizeInMapUnits", fontSizeInMapUnits );
Expand Down Expand Up @@ -587,18 +603,29 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF* fm, QString t
return;
}

QString wrapchr = !wrapChar.isEmpty() ? wrapChar : QString( "\n" );

//consider the space needed for the direction symbol
if ( addDirectionSymbol && placement == QgsPalLayerSettings::Line )
if ( addDirectionSymbol && placement == QgsPalLayerSettings::Line
&& ( !leftDirectionSymbol.isEmpty() || !rightDirectionSymbol.isEmpty() ) )
{
text.append( ">" );
QString dirSym = leftDirectionSymbol;

if ( fm->width( rightDirectionSymbol ) > fm->width( dirSym ) )
dirSym = rightDirectionSymbol;

if ( placeDirectionSymbol == QgsPalLayerSettings::SymbolLeftRight )
{
text.append( dirSym );
}
else
{
text.append( dirSym + wrapchr ); // SymbolAbove or SymbolBelow
}
}

double w = 0.0, h = 0.0;
QStringList multiLineSplit;
if ( !wrapChar.isEmpty() )
multiLineSplit = text.split( wrapChar );
else
multiLineSplit = text.split( "\n" );
QStringList multiLineSplit = text.split( wrapchr );
int lines = multiLineSplit.size();

double labelHeight = fm->ascent() + fm->descent(); // ignore +1 for baseline
Expand Down Expand Up @@ -1722,28 +1749,59 @@ void QgsPalLabeling::drawLabel( pal::LabelPosition* label, QPainter* painter, co
QString txt = ( label->getPartId() == -1 ? text : QString( text[label->getPartId()] ) );
QFontMetricsF* labelfm = (( QgsPalGeometry* )label->getFeaturePart()->getUserGeometry() )->getLabelFontMetrics();

QString wrapchr = !lyr.wrapChar.isEmpty() ? lyr.wrapChar : QString( "\n" );

//add the direction symbol if needed
if ( !txt.isEmpty() && lyr.placement == QgsPalLayerSettings::Line &&
lyr.addDirectionSymbol )
{
bool prependSymb = false;
QString symb = lyr.rightDirectionSymbol;

if ( label->getReversed() )
{
txt.prepend( "<" );
prependSymb = true;
symb = lyr.leftDirectionSymbol;
}

if ( lyr.reverseDirectionSymbol )
{
if ( symb == lyr.rightDirectionSymbol )
{
prependSymb = true;
symb = lyr.leftDirectionSymbol;
}
else
{
prependSymb = false;
symb = lyr.rightDirectionSymbol;
}
}

if ( lyr.placeDirectionSymbol == QgsPalLayerSettings::SymbolAbove )
{
prependSymb = true;
symb = symb + wrapchr;
}
else if ( lyr.placeDirectionSymbol == QgsPalLayerSettings::SymbolBelow )
{
prependSymb = false;
symb = wrapchr + symb;
}

if ( prependSymb )
{
txt.prepend( symb );
}
else
{
txt.append( ">" );
txt.append( symb );
}
}

//QgsDebugMsg( "drawLabel " + QString::number( drawBuffer ) + " " + txt );

QStringList multiLineList;
if ( !lyr.wrapChar.isEmpty() )
multiLineList = txt.split( lyr.wrapChar );
else
multiLineList = txt.split( "\n" );

QStringList multiLineList = txt.split( wrapchr );
int lines = multiLineList.size();

double labelWidest = 0.0;
Expand Down
14 changes: 13 additions & 1 deletion src/core/qgspallabeling.h
Expand Up @@ -88,6 +88,13 @@ class CORE_EXPORT QgsPalLayerSettings
ShowAll // show upside down for all labels, including dynamic ones
};

enum DirectionSymbols
{
SymbolLeftRight, // place direction symbols on left/right of label
SymbolAbove, // place direction symbols on above label
SymbolBelow // place direction symbols on below label
};

enum MultiLineAlign
{
MultiLeft = 0,
Expand Down Expand Up @@ -171,9 +178,14 @@ class CORE_EXPORT QgsPalLayerSettings
bool displayAll; // if true, all features will be labelled even though overlaps occur
bool mergeLines;
double minFeatureSize; // minimum feature size to be labelled (in mm)
// Adds '<' or '>' to the label string pointing to the direction of the line / polygon ring
// Adds '<' or '>', or user-defined symbol to the label string pointing to the
// direction of the line / polygon ring
// Works only if Placement == Line
bool addDirectionSymbol;
QString leftDirectionSymbol;
QString rightDirectionSymbol;
bool reverseDirectionSymbol;
DirectionSymbols placeDirectionSymbol; // whether to place left/right, above or below label
unsigned int upsidedownLabels; // whether, or how, to show upsidedown labels
bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
bool fontLimitPixelSize; // true is label should be limited by fontMinPixelSize/fontMaxPixelSize
Expand Down
3 changes: 3 additions & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -48,6 +48,7 @@ qgisinterface.cpp
qgsannotationitem.cpp
qgsattributeeditor.cpp
qgslegendinterface.cpp
qgscharacterselectdialog.cpp
qgscolorbutton.cpp
qgscomposerview.cpp
qgscursors.cpp
Expand Down Expand Up @@ -151,6 +152,7 @@ attributetable/qgsattributetablememorymodel.h
attributetable/qgsattributetabledelegate.h

qgsattributeeditor.h
qgscharacterselectdialog.h
qgscomposerview.h
qgsdetaileditemdelegate.h
qgsdetaileditemwidget.h
Expand Down Expand Up @@ -198,6 +200,7 @@ QT4_WRAP_CPP(QGIS_GUI_MOC_SRCS ${QGIS_GUI_MOC_HDRS})
SET(QGIS_GUI_HDRS
qgisgui.h
qgisinterface.h
qgscharacterselectdialog.h
qgscolorbutton.h
qgscursors.h
qgsencodingfiledialog.h
Expand Down

0 comments on commit bb947b4

Please sign in to comment.