Skip to content

Commit

Permalink
[FEATURE][callouts] Allow specifying an offset from label area distance
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed Jul 22, 2019
1 parent 81c4b81 commit aab8e51
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 5 deletions.
59 changes: 59 additions & 0 deletions python/core/auto_generated/callouts/qgscallout.sip.in
Expand Up @@ -45,6 +45,7 @@ relevant symbology elements to render them.
{
MinimumCalloutLength,
OffsetFromAnchor,
OffsetFromLabel,
};

enum DrawOrder
Expand Down Expand Up @@ -420,6 +421,64 @@ Returns the map unit scale for the minimum callout length.
.. seealso:: :py:func:`offsetFromAnchorUnit`

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

double offsetFromLabel() const;
%Docstring
Returns the offset distance from label area at which to end the line. Units are specified through offsetFromLabelUnit().

.. seealso:: :py:func:`setOffsetFromLabel`

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

void setOffsetFromLabel( double distance );
%Docstring
Sets the offset ``distance`` from label area at which to end the line. Units are specified through setOffsetFromLabelUnit().

.. seealso:: :py:func:`offsetFromLabel`

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

void setOffsetFromLabelUnit( QgsUnitTypes::RenderUnit unit );
%Docstring
Sets the ``unit`` for the offset from label area distance.

.. seealso:: :py:func:`offsetFromLabel`

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

QgsUnitTypes::RenderUnit offsetFromLabelUnit() const;
%Docstring
Returns the units for the offset from label area.

.. seealso:: :py:func:`setOffsetFromLabelUnit`

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

void setOffsetFromLabelMapUnitScale( const QgsMapUnitScale &scale );
%Docstring
Sets the map unit ``scale`` for the offset from label area.

.. seealso:: :py:func:`offsetFromLabelMapUnitScale`

.. seealso:: :py:func:`setOffsetFromLabelUnit`

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

const QgsMapUnitScale &offsetFromLabelMapUnitScale() const;
%Docstring
Returns the map unit scale for the minimum callout length.

.. seealso:: :py:func:`setOffsetFromLabelMapUnitScale`

.. seealso:: :py:func:`offsetFromLabelUnit`

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

protected:
Expand Down
31 changes: 27 additions & 4 deletions src/core/callouts/qgscallout.cpp
Expand Up @@ -22,6 +22,7 @@
#include "qgssymbollayerutils.h"
#include "qgsxmlutils.h"
#include "qgslinestring.h"
#include "qgslogger.h"
#include <QPainter>
#include <mutex>

Expand Down Expand Up @@ -164,6 +165,9 @@ QgsSimpleLineCallout::QgsSimpleLineCallout( const QgsSimpleLineCallout &other )
, mOffsetFromAnchorDistance( other.mOffsetFromAnchorDistance )
, mOffsetFromAnchorUnit( other.mOffsetFromAnchorUnit )
, mOffsetFromAnchorScale( other.mOffsetFromAnchorScale )
, mOffsetFromLabelDistance( other.mOffsetFromLabelDistance )
, mOffsetFromLabelUnit( other.mOffsetFromLabelUnit )
, mOffsetFromLabelScale( other.mOffsetFromLabelScale )
{

}
Expand Down Expand Up @@ -200,6 +204,9 @@ QVariantMap QgsSimpleLineCallout::properties( const QgsReadWriteContext &context
props[ QStringLiteral( "offsetFromAnchor" ) ] = mOffsetFromAnchorDistance;
props[ QStringLiteral( "offsetFromAnchorUnit" ) ] = QgsUnitTypes::encodeUnit( mOffsetFromAnchorUnit );
props[ QStringLiteral( "offsetFromAnchorMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetFromAnchorScale );
props[ QStringLiteral( "offsetFromLabel" ) ] = mOffsetFromLabelDistance;
props[ QStringLiteral( "offsetFromLabelUnit" ) ] = QgsUnitTypes::encodeUnit( mOffsetFromLabelUnit );
props[ QStringLiteral( "offsetFromLabelMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetFromLabelScale );

return props;
}
Expand All @@ -223,6 +230,9 @@ void QgsSimpleLineCallout::readProperties( const QVariantMap &props, const QgsRe
mOffsetFromAnchorDistance = props.value( QStringLiteral( "offsetFromAnchor" ), 0 ).toDouble();
mOffsetFromAnchorUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "offsetFromAnchorUnit" ) ).toString() );
mOffsetFromAnchorScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "offsetFromAnchorMapUnitScale" ) ).toString() );
mOffsetFromLabelDistance = props.value( QStringLiteral( "offsetFromLabel" ), 0 ).toDouble();
mOffsetFromLabelUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "offsetFromLabelUnit" ) ).toString() );
mOffsetFromLabelScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "offsetFromLabelMapUnitScale" ) ).toString() );
}

void QgsSimpleLineCallout::startRender( QgsRenderContext &context )
Expand Down Expand Up @@ -302,11 +312,17 @@ void QgsSimpleLineCallout::draw( QgsRenderContext &context, QRectF rect, const d
}
const double offsetFromAnchorPixels = context.convertToPainterUnits( offsetFromAnchor, mOffsetFromAnchorUnit, mOffsetFromAnchorScale );

if ( offsetFromAnchorPixels > 0 )
double offsetFromLabel = mOffsetFromLabelDistance;
if ( dataDefinedProperties().isActive( QgsCallout::OffsetFromLabel ) )
{
offsetFromLabel = dataDefinedProperties().valueAsDouble( QgsCallout::OffsetFromLabel, context.expressionContext(), offsetFromLabel );
}
const double offsetFromLabelPixels = context.convertToPainterUnits( offsetFromLabel, mOffsetFromLabelUnit, mOffsetFromLabelScale );
if ( offsetFromAnchorPixels > 0 || offsetFromLabelPixels > 0 )
{
if ( QgsLineString *ls = qgsgeometry_cast< QgsLineString * >( line.get() ) )
{
line = QgsGeometry( ls->curveSubstring( 0, ls->length() - offsetFromAnchorPixels ) );
line = QgsGeometry( ls->curveSubstring( offsetFromLabelPixels, ls->length() - offsetFromAnchorPixels ) );
}
}

Expand Down Expand Up @@ -397,11 +413,18 @@ void QgsManhattanLineCallout::draw( QgsRenderContext &context, QRectF rect, cons
}
const double offsetFromAnchorPixels = context.convertToPainterUnits( offsetFromAnchorDist, offsetFromAnchorUnit(), offsetFromAnchorMapUnitScale() );

if ( offsetFromAnchorPixels > 0 )
double offsetFromLabelDist = offsetFromLabel();
if ( dataDefinedProperties().isActive( QgsCallout::OffsetFromLabel ) )
{
offsetFromLabelDist = dataDefinedProperties().valueAsDouble( QgsCallout::OffsetFromLabel, context.expressionContext(), offsetFromLabelDist );
}
const double offsetFromLabelPixels = context.convertToPainterUnits( offsetFromLabelDist, offsetFromAnchorUnit(), offsetFromAnchorMapUnitScale() );

if ( offsetFromAnchorPixels > 0 || offsetFromLabelPixels > 0 )
{
if ( QgsLineString *ls = qgsgeometry_cast< QgsLineString * >( line.get() ) )
{
line = QgsGeometry( ls->curveSubstring( 0, ls->length() - offsetFromAnchorPixels ) );
line = QgsGeometry( ls->curveSubstring( offsetFromLabelPixels, ls->length() - offsetFromAnchorPixels ) );
}
}

Expand Down
49 changes: 49 additions & 0 deletions src/core/callouts/qgscallout.h
Expand Up @@ -70,6 +70,7 @@ class CORE_EXPORT QgsCallout
{
MinimumCalloutLength, //!< Minimum length of callouts
OffsetFromAnchor, //!< Distance to offset lines from anchor points
OffsetFromLabel, //!< Distance to offset lines from label area
};

//! Options for draw order (stacking) of callouts
Expand Down Expand Up @@ -429,6 +430,50 @@ class CORE_EXPORT QgsSimpleLineCallout : public QgsCallout
*/
const QgsMapUnitScale &offsetFromAnchorMapUnitScale() const { return mOffsetFromAnchorScale; }

/**
* Returns the offset distance from label area at which to end the line. Units are specified through offsetFromLabelUnit().
* \see setOffsetFromLabel()
* \see offsetFromLabelUnit()
*/
double offsetFromLabel() const { return mOffsetFromLabelDistance; }

/**
* Sets the offset \a distance from label area at which to end the line. Units are specified through setOffsetFromLabelUnit().
* \see offsetFromLabel()
* \see setOffsetFromLabelUnit()
*/
void setOffsetFromLabel( double distance ) { mOffsetFromLabelDistance = distance; }

/**
* Sets the \a unit for the offset from label area distance.
* \see offsetFromLabel()
* \see setOffsetFromLabel()
*/
void setOffsetFromLabelUnit( QgsUnitTypes::RenderUnit unit ) { mOffsetFromLabelUnit = unit; }

/**
* Returns the units for the offset from label area.
* \see setOffsetFromLabelUnit()
* \see offsetFromLabel()
*/
QgsUnitTypes::RenderUnit offsetFromLabelUnit() const { return mOffsetFromLabelUnit; }

/**
* Sets the map unit \a scale for the offset from label area.
* \see offsetFromLabelMapUnitScale()
* \see setOffsetFromLabelUnit()
* \see setOffsetFromLabel()
*/
void setOffsetFromLabelMapUnitScale( const QgsMapUnitScale &scale ) { mOffsetFromLabelScale = scale; }

/**
* Returns the map unit scale for the minimum callout length.
* \see setOffsetFromLabelMapUnitScale()
* \see offsetFromLabelUnit()
* \see offsetFromLabel()
*/
const QgsMapUnitScale &offsetFromLabelMapUnitScale() const { return mOffsetFromLabelScale; }

protected:
void draw( QgsRenderContext &context, QRectF bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext ) override;

Expand All @@ -447,6 +492,10 @@ class CORE_EXPORT QgsSimpleLineCallout : public QgsCallout
double mOffsetFromAnchorDistance = 0;
QgsUnitTypes::RenderUnit mOffsetFromAnchorUnit = QgsUnitTypes::RenderMillimeters;
QgsMapUnitScale mOffsetFromAnchorScale;

double mOffsetFromLabelDistance = 0;
QgsUnitTypes::RenderUnit mOffsetFromLabelUnit = QgsUnitTypes::RenderMillimeters;
QgsMapUnitScale mOffsetFromLabelScale;
};


Expand Down
24 changes: 23 additions & 1 deletion src/gui/callouts/qgscalloutwidget.cpp
Expand Up @@ -147,12 +147,16 @@ QgsSimpleLineCalloutWidget::QgsSimpleLineCalloutWidget( QgsVectorLayer *vl, QWid
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
mOffsetFromAnchorUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
mOffsetFromLabelUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );

connect( mMinCalloutWidthUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsSimpleLineCalloutWidget::minimumLengthUnitWidgetChanged );
connect( mMinCalloutLengthSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleLineCalloutWidget::minimumLengthChanged );

connect( mOffsetFromAnchorUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsSimpleLineCalloutWidget::offsetFromAnchorUnitWidgetChanged );
connect( mOffsetFromAnchorSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleLineCalloutWidget::offsetFromAnchorChanged );
connect( mOffsetFromLabelUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsSimpleLineCalloutWidget::offsetFromLabelUnitWidgetChanged );
connect( mOffsetFromLabelSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleLineCalloutWidget::offsetFromLabelChanged );

connect( mCalloutLineStyleButton, &QgsSymbolButton::changed, this, &QgsSimpleLineCalloutWidget::lineSymbolChanged );
}
Expand All @@ -177,13 +181,18 @@ void QgsSimpleLineCalloutWidget::setCallout( QgsCallout *callout )
mOffsetFromAnchorUnitWidget->setUnit( mCallout->offsetFromAnchorUnit() );
mOffsetFromAnchorUnitWidget->setMapUnitScale( mCallout->offsetFromAnchorMapUnitScale() );
mOffsetFromAnchorUnitWidget->blockSignals( false );

mOffsetFromLabelUnitWidget->blockSignals( true );
mOffsetFromLabelUnitWidget->setUnit( mCallout->offsetFromLabelUnit() );
mOffsetFromLabelUnitWidget->setMapUnitScale( mCallout->offsetFromLabelMapUnitScale() );
mOffsetFromLabelUnitWidget->blockSignals( false );
whileBlocking( mOffsetFromAnchorSpin )->setValue( mCallout->offsetFromAnchor() );
whileBlocking( mOffsetFromLabelSpin )->setValue( mCallout->offsetFromLabel() );

whileBlocking( mCalloutLineStyleButton )->setSymbol( mCallout->lineSymbol()->clone() );

registerDataDefinedButton( mMinCalloutLengthDDBtn, QgsCallout::MinimumCalloutLength );
registerDataDefinedButton( mOffsetFromAnchorDDBtn, QgsCallout::OffsetFromAnchor );
registerDataDefinedButton( mOffsetFromLabelDDBtn, QgsCallout::OffsetFromLabel );
}

QgsCallout *QgsSimpleLineCalloutWidget::callout()
Expand Down Expand Up @@ -217,6 +226,19 @@ void QgsSimpleLineCalloutWidget::offsetFromAnchorChanged()
emit changed();
}

void QgsSimpleLineCalloutWidget::offsetFromLabelUnitWidgetChanged()
{
mCallout->setOffsetFromLabelUnit( mOffsetFromLabelUnitWidget->unit() );
mCallout->setOffsetFromLabelMapUnitScale( mOffsetFromLabelUnitWidget->getMapUnitScale() );
emit changed();
}

void QgsSimpleLineCalloutWidget::offsetFromLabelChanged()
{
mCallout->setOffsetFromLabel( mOffsetFromLabelSpin->value() );
emit changed();
}

void QgsSimpleLineCalloutWidget::lineSymbolChanged()
{
mCallout->setLineSymbol( mCalloutLineStyleButton->clonedSymbol< QgsLineSymbol >() );
Expand Down
2 changes: 2 additions & 0 deletions src/gui/callouts/qgscalloutwidget.h
Expand Up @@ -143,6 +143,8 @@ class GUI_EXPORT QgsSimpleLineCalloutWidget : public QgsCalloutWidget, private U
void minimumLengthUnitWidgetChanged();
void offsetFromAnchorUnitWidgetChanged();
void offsetFromAnchorChanged();
void offsetFromLabelUnitWidgetChanged();
void offsetFromLabelChanged();
void lineSymbolChanged();

private:
Expand Down
55 changes: 55 additions & 0 deletions src/ui/callouts/widget_simplelinecallout.ui
Expand Up @@ -158,6 +158,58 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_47">
<property name="text">
<string>Offset from label area</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QgsDoubleSpinBox" name="mOffsetFromLabelSpin">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>100000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.200000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
<property name="showClearButton" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QgsPropertyOverrideButton" name="mOffsetFromLabelDDBtn">
<property name="text">
<string>…</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QgsUnitSelectionWidget" name="mOffsetFromLabelUnitWidget" native="true">
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
Expand Down Expand Up @@ -206,6 +258,9 @@
<tabstop>mOffsetFromAnchorSpin</tabstop>
<tabstop>mOffsetFromAnchorUnitWidget</tabstop>
<tabstop>mOffsetFromAnchorDDBtn</tabstop>
<tabstop>mOffsetFromLabelSpin</tabstop>
<tabstop>mOffsetFromLabelUnitWidget</tabstop>
<tabstop>mOffsetFromLabelDDBtn</tabstop>
</tabstops>
<resources/>
<connections/>
Expand Down

0 comments on commit aab8e51

Please sign in to comment.