Skip to content
Permalink
Browse files

[feature][labeling] Add option to allow users to control the placement

of labels along line features

The new "Label Anchoring" section in the line placement settings for
labels allows users to specify whether labels should be placed
at the center, start or end of lines (or a custom percent from the
start of the line). Also allows data-defined percent along line
control!
  • Loading branch information
nyalldawson committed Aug 18, 2020
1 parent b14bb32 commit 748d76aeed815e8a6b1d34ba38e65b7416444b53
@@ -0,0 +1,57 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/labeling/qgslabellineanchorwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/



class QgsLabelLineAnchorWidget : QgsLabelSettingsWidgetBase
{
%Docstring
A widget for customising label line anchor settings.

.. versionadded:: 3.16
%End

%TypeHeaderCode
#include "qgslabellineanchorwidget.h"
%End
public:

QgsLabelLineAnchorWidget( QWidget *parent /TransferThis/ = 0, QgsVectorLayer *vl = 0 );
%Docstring
Constructor for QgsLabelLineAnchorWidget.

:param parent: parent widget
:param vl: associated vector layer
%End

void setSettings( const QgsLabelLineSettings &settings );
%Docstring
Sets the line ``settings`` to show in the widget.

.. seealso:: :py:func:`settings`
%End

QgsLabelLineSettings settings() const;
%Docstring
Returns the line settings defined by the widget.

.. seealso:: :py:func:`setSettings`
%End

virtual void updateDataDefinedProperties( QgsPropertyCollection &properties );


};

/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/labeling/qgslabellineanchorwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
@@ -287,6 +287,7 @@
%Include auto_generated/effects/qgseffectstackpropertieswidget.sip
%Include auto_generated/effects/qgspainteffectpropertieswidget.sip
%Include auto_generated/effects/qgspainteffectwidget.sip
%Include auto_generated/labeling/qgslabellineanchorwidget.sip
%Include auto_generated/labeling/qgslabelobstaclesettingswidget.sip
%Include auto_generated/labeling/qgslabelsettingswidgetbase.sip
%Include auto_generated/layertree/qgscustomlayerorderwidget.sip
@@ -189,6 +189,7 @@ SET(QGIS_GUI_SRCS
labeling/qgslabelengineconfigdialog.cpp
labeling/qgslabelinggui.cpp
labeling/qgslabelingwidget.cpp
labeling/qgslabellineanchorwidget.cpp
labeling/qgslabelobstaclesettingswidget.cpp
labeling/qgslabelsettingswidgetbase.cpp
labeling/qgsrulebasedlabelingwidget.cpp
@@ -926,6 +927,7 @@ SET(QGIS_GUI_HDRS
labeling/qgslabelengineconfigdialog.h
labeling/qgslabelinggui.h
labeling/qgslabelingwidget.h
labeling/qgslabellineanchorwidget.h
labeling/qgslabelobstaclesettingswidget.h
labeling/qgslabelsettingswidgetbase.h
labeling/qgsrulebasedlabelingwidget.h
@@ -31,6 +31,7 @@
#include "qgscalloutsregistry.h"
#include "callouts/qgscalloutwidget.h"
#include "qgslabelobstaclesettingswidget.h"
#include "qgslabellineanchorwidget.h"
#include <mutex>

#include <QButtonGroup>
@@ -176,6 +177,50 @@ void QgsLabelingGui::showObstacleSettings()
}
}

void QgsLabelingGui::showLineAnchorSettings()
{
QgsExpressionContext context = createExpressionContext();

QgsSymbolWidgetContext symbolContext;
symbolContext.setExpressionContext( &context );
symbolContext.setMapCanvas( mMapCanvas );

QgsLabelLineAnchorWidget *widget = new QgsLabelLineAnchorWidget( nullptr, mLayer );
widget->setDataDefinedProperties( mDataDefinedProperties );
widget->setSettings( mLineSettings );
widget->setGeometryType( mLayer ? mLayer->geometryType() : QgsWkbTypes::UnknownGeometry );
widget->setContext( symbolContext );

auto applySettings = [ = ]
{
const QgsLabelLineSettings widgetSettings = widget->settings();
mLineSettings.setLineAnchorPercent( widgetSettings.lineAnchorPercent() );
const QgsPropertyCollection obstacleDataDefinedProperties = widget->dataDefinedProperties();
widget->updateDataDefinedProperties( mDataDefinedProperties );
emit widgetChanged();
};

QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
if ( panel && panel->dockMode() )
{
connect( widget, &QgsLabelSettingsWidgetBase::changed, this, [ = ]
{
applySettings();
} );
panel->openPanel( widget );
}
else
{
QgsLabelSettingsWidgetDialog dialog( widget, this );
if ( dialog.exec() )
{
applySettings();
}
// reactivate button's window
activateWindow();
}
}

QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsPalLayerSettings &layerSettings, QWidget *parent, QgsWkbTypes::GeometryType geomType )
: QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, layer )
, mGeomType( geomType )
@@ -211,6 +256,7 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas,
connect( mGeometryGenerator, &QgsCodeEditorExpression::textChanged, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::validateGeometryGeneratorExpression );
connect( mObstacleSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingGui::showObstacleSettings );
connect( mLineAnchorSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingGui::showLineAnchorSettings );

mFieldExpressionWidget->registerExpressionContextGenerator( this );

@@ -353,6 +399,7 @@ void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
mChkNoObstacle->setChecked( mSettings.obstacleSettings().isObstacle() );

mObstacleSettings = mSettings.obstacleSettings();
mLineSettings = mSettings.lineSettings();

chkLabelPerFeaturePart->setChecked( mSettings.labelPerPart );
mPalShowAllLabelsForLayerChkBx->setChecked( mSettings.displayAll );
@@ -566,6 +613,8 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
mObstacleSettings.setIsObstacle( mChkNoObstacle->isChecked() || mMode == ObstaclesOnly );
lyr.setObstacleSettings( mObstacleSettings );

lyr.lineSettings().setLineAnchorPercent( mLineSettings.lineAnchorPercent() );

lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
lyr.lineSettings().setMergeLines( chkMergeLines->isChecked() );
@@ -92,6 +92,7 @@ class GUI_EXPORT QgsLabelingGui : public QgsTextFormatWidget
QgsMapCanvas *mCanvas = nullptr;

QgsLabelObstacleSettings mObstacleSettings;
QgsLabelLineSettings mLineSettings;

QgsExpressionContext createExpressionContext() const override;

@@ -100,6 +101,7 @@ class GUI_EXPORT QgsLabelingGui : public QgsTextFormatWidget
void initCalloutWidgets();
void updateCalloutWidget( QgsCallout *callout );
void showObstacleSettings();
void showLineAnchorSettings();

};

@@ -0,0 +1,85 @@
/***************************************************************************
qgslabellineanchorwidget.cpp
----------------------
begin : August 2020
copyright : (C) 2020 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/


#include "qgslabellineanchorwidget.h"
#include "qgsexpressioncontextutils.h"

QgsLabelLineAnchorWidget::QgsLabelLineAnchorWidget( QWidget *parent, QgsVectorLayer *vl )
: QgsLabelSettingsWidgetBase( parent, vl )
{
setupUi( this );

setPanelTitle( tr( "Line Anchor Settings" ) );

mPercentPlacementComboBox->addItem( tr( "Center of Line" ), 0.5 );
mPercentPlacementComboBox->addItem( tr( "Start of Line" ), 0.0 );
mPercentPlacementComboBox->addItem( tr( "End of Line" ), 1.0 );
mPercentPlacementComboBox->addItem( tr( "Custom" ), -1.0 );

connect( mPercentPlacementComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]( int )
{
if ( !mBlockSignals )
emit changed();

mCustomPlacementSpinBox->setEnabled( mPercentPlacementComboBox->currentData().toDouble() < 0 );
} );
connect( mCustomPlacementSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, [ = ]( double )
{
if ( !mBlockSignals )
emit changed();
} );

registerDataDefinedButton( mLinePlacementDDBtn, QgsPalLayerSettings::LineAnchorPercent );

}

void QgsLabelLineAnchorWidget::setSettings( const QgsLabelLineSettings &settings )
{
mBlockSignals = true;
const int comboIndex = mPercentPlacementComboBox->findData( settings.lineAnchorPercent() );
if ( comboIndex >= 0 )
{
mPercentPlacementComboBox->setCurrentIndex( comboIndex );
}
else
{
// set custom control
mPercentPlacementComboBox->setCurrentIndex( mPercentPlacementComboBox->findData( -1.0 ) );
mCustomPlacementSpinBox->setValue( settings.lineAnchorPercent() * 100.0 );
}
mCustomPlacementSpinBox->setEnabled( mPercentPlacementComboBox->currentData().toDouble() < 0 );
mBlockSignals = false;
}

QgsLabelLineSettings QgsLabelLineAnchorWidget::settings() const
{
QgsLabelLineSettings settings;

if ( mPercentPlacementComboBox->currentData().toDouble() >= 0 )
{
settings.setLineAnchorPercent( mPercentPlacementComboBox->currentData().toDouble() );
}
else
{
settings.setLineAnchorPercent( mCustomPlacementSpinBox->value() / 100.0 );
}
return settings;
}

void QgsLabelLineAnchorWidget::updateDataDefinedProperties( QgsPropertyCollection &properties )
{
properties.setProperty( QgsPalLayerSettings::LineAnchorPercent, mDataDefinedProperties.property( QgsPalLayerSettings::LineAnchorPercent ) );
}
@@ -0,0 +1,66 @@
/***************************************************************************
qgslabellineanchorwidget.h
----------------------
begin : August 2020
copyright : (C) 2020 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSLABELLINEANCHORWIDGET_H
#define QGSLABELLINEANCHORWIDGET_H

#include "ui_qgslabellineanchorwidgetbase.h"
#include "qgslabelsettingswidgetbase.h"
#include "qgspallabeling.h"
#include "qgis_gui.h"
#include "qgis_sip.h"

/**
* \ingroup gui
* \class QgsLabelLineAnchorWidget
* A widget for customising label line anchor settings.
* \since QGIS 3.16
*/
class GUI_EXPORT QgsLabelLineAnchorWidget : public QgsLabelSettingsWidgetBase, private Ui::QgsLabelLineAnchorWidgetBase
{
Q_OBJECT

public:

/**
* Constructor for QgsLabelLineAnchorWidget.
* \param parent parent widget
* \param vl associated vector layer
*/
QgsLabelLineAnchorWidget( QWidget *parent SIP_TRANSFERTHIS = nullptr, QgsVectorLayer *vl = nullptr );

/**
* Sets the line \a settings to show in the widget.
*
* \see settings()
*/
void setSettings( const QgsLabelLineSettings &settings );

/**
* Returns the line settings defined by the widget.
*
* \see setSettings()
*/
QgsLabelLineSettings settings() const;

void updateDataDefinedProperties( QgsPropertyCollection &properties ) override;

private:

bool mBlockSignals = false;

};

#endif // QGSLABELLINEANCHORWIDGET_H
@@ -1393,6 +1393,7 @@ void QgsTextFormatWidget::updatePlacementWidgets()
mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon &&
( radPolygonPerimeter->isChecked() || radPolygonPerimeterCurved->isChecked() ) ) );
mPlacementOverrunDistanceFrame->setVisible( curWdgt == pageLine );
mLineAnchorGroupBox->setVisible( curWdgt == pageLine );
mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame );

mMultiLinesFrame->setEnabled( enableMultiLinesFrame );

0 comments on commit 748d76a

Please sign in to comment.
You can’t perform that action at this time.