Skip to content

Commit

Permalink
[FEATURE] Allow data defined settings in text formats
Browse files Browse the repository at this point in the history
This allows text formats to store data defined settings,
allowing them to be used wherever the text renderer is (e.g. in
layout scalebar text).
  • Loading branch information
nyalldawson committed Jul 22, 2019
1 parent 19a2b0e commit a85d4d1
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 336 deletions.
24 changes: 23 additions & 1 deletion python/gui/auto_generated/qgstextformatwidget.sip.in
Expand Up @@ -47,9 +47,12 @@ Constructor for QgsTextFormatWidget.

~QgsTextFormatWidget();

QgsTextFormat format() const;
QgsTextFormat format( bool includeDataDefinedProperties = true ) const;
%Docstring
Returns the current formatting settings defined by the widget.

If ``includateDataDefinedProperties`` is ``True``, then data defined properties
specified in the widget will be included in the format definition.
%End

void setFormat( const QgsTextFormat &format );
Expand All @@ -75,6 +78,16 @@ Returns the context in which the widget is shown, e.g., the associated map canva
.. seealso:: :py:func:`setContext`

.. versionadded:: 3.10
%End

void deactivateField( QgsPalLayerSettings::Property key );
%Docstring
Deactivate a field from data defined properties and update the
corresponding button.

:param key: The property key to deactivate

.. versionadded:: 3.0
%End

public slots:
Expand All @@ -91,6 +104,13 @@ Sets whether the widget should be shown in a compact dock mode.
void widgetChanged();
%Docstring
Emitted when the text format defined by the widget changes
%End

void auxiliaryFieldCreated();
%Docstring
Emitted when an auxiliary field is creatd in the widget.

.. versionadded:: 3.10
%End

protected:
Expand Down Expand Up @@ -138,6 +158,7 @@ Controls whether data defined alignment buttons are enabled.




protected slots:

void updateLinePlacementOptions();
Expand Down Expand Up @@ -169,6 +190,7 @@ Updates the text preview.
.. versionadded:: 3.10
%End


};


Expand Down
210 changes: 1 addition & 209 deletions src/gui/qgslabelinggui.cpp
Expand Up @@ -57,23 +57,6 @@ QgsExpressionContext QgsLabelingGui::createExpressionContext() const
return expContext;
}

void QgsLabelingGui::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsPalLayerSettings::Property key )
{
button->init( key, mDataDefinedProperties, QgsPalLayerSettings::propertyDefinitions(), mLayer, true );
connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLabelingGui::updateProperty );
connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsLabelingGui::createAuxiliaryField );
button->registerExpressionContextGenerator( this );

mButtons[key] = button;
}

void QgsLabelingGui::updateProperty()
{
QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
QgsPalLayerSettings::Property key = static_cast< QgsPalLayerSettings::Property >( button->propertyKey() );
mDataDefinedProperties.setProperty( key, button->toProperty() );
}

static bool _initCalloutWidgetFunction( const QString &name, QgsCalloutWidgetFunc f )
{
QgsCalloutRegistry *registry = QgsApplication::calloutRegistry();
Expand Down Expand Up @@ -500,7 +483,7 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
lyr.useSubstitutions = mCheckBoxSubstituteText->isChecked();
lyr.substitutions = mSubstitutions;

lyr.setFormat( format() );
lyr.setFormat( format( false ) );

// format numbers
lyr.formatNumbers = mFormatNumChkBx->isChecked();
Expand Down Expand Up @@ -563,148 +546,6 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
return lyr;
}

void QgsLabelingGui::populateDataDefinedButtons()
{
// text style
registerDataDefinedButton( mFontDDBtn, QgsPalLayerSettings::Family );
registerDataDefinedButton( mFontStyleDDBtn, QgsPalLayerSettings::FontStyle );
registerDataDefinedButton( mFontUnderlineDDBtn, QgsPalLayerSettings::Underline );
registerDataDefinedButton( mFontStrikeoutDDBtn, QgsPalLayerSettings::Strikeout );
registerDataDefinedButton( mFontBoldDDBtn, QgsPalLayerSettings::Bold );
registerDataDefinedButton( mFontItalicDDBtn, QgsPalLayerSettings::Italic );
registerDataDefinedButton( mFontSizeDDBtn, QgsPalLayerSettings::Size );
registerDataDefinedButton( mFontUnitsDDBtn, QgsPalLayerSettings::FontSizeUnit );
registerDataDefinedButton( mFontColorDDBtn, QgsPalLayerSettings::Color );
registerDataDefinedButton( mFontOpacityDDBtn, QgsPalLayerSettings::FontOpacity );
registerDataDefinedButton( mFontCaseDDBtn, QgsPalLayerSettings::FontCase );
registerDataDefinedButton( mFontLetterSpacingDDBtn, QgsPalLayerSettings::FontLetterSpacing );
registerDataDefinedButton( mFontWordSpacingDDBtn, QgsPalLayerSettings::FontWordSpacing );
registerDataDefinedButton( mFontBlendModeDDBtn, QgsPalLayerSettings::FontBlendMode );

// text formatting
registerDataDefinedButton( mWrapCharDDBtn, QgsPalLayerSettings::MultiLineWrapChar );
registerDataDefinedButton( mAutoWrapLengthDDBtn, QgsPalLayerSettings::AutoWrapLength );
registerDataDefinedButton( mFontLineHeightDDBtn, QgsPalLayerSettings::MultiLineHeight );
registerDataDefinedButton( mFontMultiLineAlignDDBtn, QgsPalLayerSettings::MultiLineAlignment );

registerDataDefinedButton( mDirectSymbDDBtn, QgsPalLayerSettings::DirSymbDraw );
mDirectSymbDDBtn->registerCheckedWidget( mDirectSymbChkBx );
registerDataDefinedButton( mDirectSymbLeftDDBtn, QgsPalLayerSettings::DirSymbLeft );
registerDataDefinedButton( mDirectSymbRightDDBtn, QgsPalLayerSettings::DirSymbRight );

registerDataDefinedButton( mDirectSymbPlacementDDBtn, QgsPalLayerSettings::DirSymbPlacement );
registerDataDefinedButton( mDirectSymbRevDDBtn, QgsPalLayerSettings::DirSymbReverse );

registerDataDefinedButton( mFormatNumDDBtn, QgsPalLayerSettings::NumFormat );
mFormatNumDDBtn->registerCheckedWidget( mFormatNumChkBx );
registerDataDefinedButton( mFormatNumDecimalsDDBtn, QgsPalLayerSettings::NumDecimals );
registerDataDefinedButton( mFormatNumPlusSignDDBtn, QgsPalLayerSettings::NumPlusSign );

// text buffer
registerDataDefinedButton( mBufferDrawDDBtn, QgsPalLayerSettings::BufferDraw );
mBufferDrawDDBtn->registerCheckedWidget( mBufferDrawChkBx );
registerDataDefinedButton( mBufferSizeDDBtn, QgsPalLayerSettings::BufferSize );
registerDataDefinedButton( mBufferUnitsDDBtn, QgsPalLayerSettings::BufferUnit );
registerDataDefinedButton( mBufferColorDDBtn, QgsPalLayerSettings::BufferColor );
registerDataDefinedButton( mBufferOpacityDDBtn, QgsPalLayerSettings::BufferOpacity );
registerDataDefinedButton( mBufferJoinStyleDDBtn, QgsPalLayerSettings::BufferJoinStyle );
registerDataDefinedButton( mBufferBlendModeDDBtn, QgsPalLayerSettings::BufferBlendMode );

// background
registerDataDefinedButton( mShapeDrawDDBtn, QgsPalLayerSettings::ShapeDraw );
mShapeDrawDDBtn->registerCheckedWidget( mShapeDrawChkBx );
registerDataDefinedButton( mShapeTypeDDBtn, QgsPalLayerSettings::ShapeKind );
registerDataDefinedButton( mShapeSVGPathDDBtn, QgsPalLayerSettings::ShapeSVGFile );
registerDataDefinedButton( mShapeSizeTypeDDBtn, QgsPalLayerSettings::ShapeSizeType );
registerDataDefinedButton( mShapeSizeXDDBtn, QgsPalLayerSettings::ShapeSizeX );
registerDataDefinedButton( mShapeSizeYDDBtn, QgsPalLayerSettings::ShapeSizeY );
registerDataDefinedButton( mShapeSizeUnitsDDBtn, QgsPalLayerSettings::ShapeSizeUnits );
registerDataDefinedButton( mShapeRotationTypeDDBtn, QgsPalLayerSettings::ShapeRotationType );
registerDataDefinedButton( mShapeRotationDDBtn, QgsPalLayerSettings::ShapeRotation );
registerDataDefinedButton( mShapeOffsetDDBtn, QgsPalLayerSettings::ShapeOffset );
registerDataDefinedButton( mShapeOffsetUnitsDDBtn, QgsPalLayerSettings::ShapeOffsetUnits );
registerDataDefinedButton( mShapeRadiusDDBtn, QgsPalLayerSettings::ShapeRadii );
registerDataDefinedButton( mShapeRadiusUnitsDDBtn, QgsPalLayerSettings::ShapeRadiiUnits );
registerDataDefinedButton( mShapeOpacityDDBtn, QgsPalLayerSettings::ShapeOpacity );
registerDataDefinedButton( mShapeBlendModeDDBtn, QgsPalLayerSettings::ShapeBlendMode );
registerDataDefinedButton( mShapeFillColorDDBtn, QgsPalLayerSettings::ShapeFillColor );
registerDataDefinedButton( mShapeStrokeColorDDBtn, QgsPalLayerSettings::ShapeStrokeColor );
registerDataDefinedButton( mShapeStrokeWidthDDBtn, QgsPalLayerSettings::ShapeStrokeWidth );
registerDataDefinedButton( mShapeStrokeUnitsDDBtn, QgsPalLayerSettings::ShapeStrokeWidthUnits );
registerDataDefinedButton( mShapePenStyleDDBtn, QgsPalLayerSettings::ShapeJoinStyle );

// drop shadows
registerDataDefinedButton( mShadowDrawDDBtn, QgsPalLayerSettings::ShadowDraw );
mShadowDrawDDBtn->registerCheckedWidget( mShadowDrawChkBx );
registerDataDefinedButton( mShadowUnderDDBtn, QgsPalLayerSettings::ShadowUnder );
registerDataDefinedButton( mShadowOffsetAngleDDBtn, QgsPalLayerSettings::ShadowOffsetAngle );
registerDataDefinedButton( mShadowOffsetDDBtn, QgsPalLayerSettings::ShadowOffsetDist );
registerDataDefinedButton( mShadowOffsetUnitsDDBtn, QgsPalLayerSettings::ShadowOffsetUnits );
registerDataDefinedButton( mShadowRadiusDDBtn, QgsPalLayerSettings::ShadowRadius );
registerDataDefinedButton( mShadowRadiusUnitsDDBtn, QgsPalLayerSettings::ShadowRadiusUnits );
registerDataDefinedButton( mShadowOpacityDDBtn, QgsPalLayerSettings::ShadowOpacity );
registerDataDefinedButton( mShadowScaleDDBtn, QgsPalLayerSettings::ShadowScale );
registerDataDefinedButton( mShadowColorDDBtn, QgsPalLayerSettings::ShadowColor );
registerDataDefinedButton( mShadowBlendDDBtn, QgsPalLayerSettings::ShadowBlendMode );

// placement
registerDataDefinedButton( mCentroidDDBtn, QgsPalLayerSettings::CentroidWhole );
registerDataDefinedButton( mPointQuadOffsetDDBtn, QgsPalLayerSettings::OffsetQuad );
registerDataDefinedButton( mPointPositionOrderDDBtn, QgsPalLayerSettings::PredefinedPositionOrder );
registerDataDefinedButton( mLinePlacementFlagsDDBtn, QgsPalLayerSettings::LinePlacementOptions );
registerDataDefinedButton( mPointOffsetDDBtn, QgsPalLayerSettings::OffsetXY );
registerDataDefinedButton( mPointOffsetUnitsDDBtn, QgsPalLayerSettings::OffsetUnits );
registerDataDefinedButton( mLineDistanceDDBtn, QgsPalLayerSettings::LabelDistance );
registerDataDefinedButton( mLineDistanceUnitDDBtn, QgsPalLayerSettings::DistanceUnits );
registerDataDefinedButton( mPriorityDDBtn, QgsPalLayerSettings::Priority );

// TODO: is this necessary? maybe just use the data defined-only rotation?
//mPointAngleDDBtn, QgsPalLayerSettings::OffsetRotation,
// QgsPropertyOverrideButton::AnyType, QgsPropertyOverrideButton::double180RotDesc() );
registerDataDefinedButton( mMaxCharAngleDDBtn, QgsPalLayerSettings::CurvedCharAngleInOut );
registerDataDefinedButton( mRepeatDistanceDDBtn, QgsPalLayerSettings::RepeatDistance );
registerDataDefinedButton( mRepeatDistanceUnitDDBtn, QgsPalLayerSettings::RepeatDistanceUnit );

// data defined-only
QString ddPlaceInfo = tr( "In edit mode, layer's relevant labeling map tool is:<br>"
"&nbsp;&nbsp;Defined attribute field -&gt; <i>enabled</i><br>"
"&nbsp;&nbsp;Defined expression -&gt; <i>disabled</i>" );
registerDataDefinedButton( mCoordXDDBtn, QgsPalLayerSettings::PositionX );
mCoordXDDBtn->setUsageInfo( ddPlaceInfo );
registerDataDefinedButton( mCoordYDDBtn, QgsPalLayerSettings::PositionY );
mCoordYDDBtn->setUsageInfo( ddPlaceInfo );
registerDataDefinedButton( mCoordAlignmentHDDBtn, QgsPalLayerSettings::Hali );
mCoordAlignmentHDDBtn->setUsageInfo( ddPlaceInfo );
registerDataDefinedButton( mCoordAlignmentVDDBtn, QgsPalLayerSettings::Vali );
mCoordAlignmentVDDBtn->setUsageInfo( ddPlaceInfo );
registerDataDefinedButton( mCoordRotationDDBtn, QgsPalLayerSettings::LabelRotation );
mCoordRotationDDBtn->setUsageInfo( ddPlaceInfo );

// rendering
QString ddScaleVisInfo = tr( "Value &lt; 0 represents a scale closer than 1:1, e.g. -10 = 10:1<br>"
"Value of 0 disables the specific limit." );
registerDataDefinedButton( mScaleBasedVisibilityDDBtn, QgsPalLayerSettings::ScaleVisibility );
mScaleBasedVisibilityDDBtn->registerCheckedWidget( mScaleBasedVisibilityChkBx );
registerDataDefinedButton( mScaleBasedVisibilityMinDDBtn, QgsPalLayerSettings::MinimumScale );
mScaleBasedVisibilityMinDDBtn->setUsageInfo( ddScaleVisInfo );
registerDataDefinedButton( mScaleBasedVisibilityMaxDDBtn, QgsPalLayerSettings::MaximumScale );
mScaleBasedVisibilityMaxDDBtn->setUsageInfo( ddScaleVisInfo );

registerDataDefinedButton( mFontLimitPixelDDBtn, QgsPalLayerSettings::FontLimitPixel );
mFontLimitPixelDDBtn->registerCheckedWidget( mFontLimitPixelChkBox );
registerDataDefinedButton( mFontMinPixelDDBtn, QgsPalLayerSettings::FontMinPixel );
registerDataDefinedButton( mFontMaxPixelDDBtn, QgsPalLayerSettings::FontMaxPixel );

registerDataDefinedButton( mShowLabelDDBtn, QgsPalLayerSettings::Show );

registerDataDefinedButton( mAlwaysShowDDBtn, QgsPalLayerSettings::AlwaysShow );

registerDataDefinedButton( mIsObstacleDDBtn, QgsPalLayerSettings::IsObstacle );
registerDataDefinedButton( mObstacleFactorDDBtn, QgsPalLayerSettings::ObstacleFactor );
registerDataDefinedButton( mZIndexDDBtn, QgsPalLayerSettings::ZIndex );

registerDataDefinedButton( mCalloutDrawDDBtn, QgsPalLayerSettings::CalloutDraw );
}

void QgsLabelingGui::syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f )
{
Expand Down Expand Up @@ -739,41 +580,6 @@ void QgsLabelingGui::updateUi()
}
}

void QgsLabelingGui::createAuxiliaryField()
{
if ( !mLayer )
return;

// try to create an auxiliary layer if not yet created
if ( !mLayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
dlg.exec();
}

// return if still not exists
if ( !mLayer->auxiliaryLayer() )
return;

QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
const QgsPalLayerSettings::Property key = static_cast< QgsPalLayerSettings::Property >( button->propertyKey() );
const QgsPropertyDefinition def = QgsPalLayerSettings::propertyDefinitions()[key];

// create property in auxiliary storage if necessary
if ( !mLayer->auxiliaryLayer()->exists( def ) )
mLayer->auxiliaryLayer()->addAuxiliaryField( def );

// update property with join field name from auxiliary storage
QgsProperty property = button->toProperty();
property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
property.setActive( true );
button->updateFieldLists();
button->setToProperty( property );
mDataDefinedProperties.setProperty( key, button->toProperty() );

emit auxiliaryFieldCreated();
}

void QgsLabelingGui::setFormatFromStyle( const QString &name, QgsStyle::StyleEntity type )
{
switch ( type )
Expand Down Expand Up @@ -886,20 +692,6 @@ void QgsLabelingGui::saveFormat()
}
}

void QgsLabelingGui::deactivateField( QgsPalLayerSettings::Property key )
{
if ( mButtons.contains( key ) )
{
QgsPropertyOverrideButton *button = mButtons[ key ];
QgsProperty p = button->toProperty();
p.setField( QString() );
p.setActive( false );
button->updateFieldLists();
button->setToProperty( p );
mDataDefinedProperties.setProperty( key, p );
}
}

void QgsLabelingGui::updateGeometryTypeBasedWidgets()
{
QgsWkbTypes::GeometryType geometryType = mGeomType;
Expand Down
24 changes: 1 addition & 23 deletions src/gui/qgslabelinggui.h
Expand Up @@ -52,28 +52,12 @@ class GUI_EXPORT QgsLabelingGui : public QgsTextFormatWidget

void setSettings( const QgsPalLayerSettings &settings );

/**
* Deactivate a field from data defined properties and update the
* corresponding button.
*
* \param key The property key to deactivate
*
* \since QGIS 3.0
*/
void deactivateField( QgsPalLayerSettings::Property key );

void setContext( const QgsSymbolWidgetContext &context ) override;

signals:

void auxiliaryFieldCreated();

public slots:

void updateUi();

void createAuxiliaryField();

protected slots:
void setFormatFromStyle( const QString &name, QgsStyle::StyleEntity type ) override;
void saveFormat() override;
Expand All @@ -100,23 +84,17 @@ class GUI_EXPORT QgsLabelingGui : public QgsTextFormatWidget
void calloutTypeChanged();

private:

QgsWkbTypes::GeometryType mGeomType = QgsWkbTypes::UnknownGeometry;
QgsPalLayerSettings mSettings;
QgsPropertyCollection mDataDefinedProperties;
LabelMode mMode;
QgsFeature mPreviewFeature;
QgsMapCanvas *mCanvas = nullptr;

QgsExpressionContext createExpressionContext() const override;

void populateDataDefinedButtons();
void registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsPalLayerSettings::Property key );

QMap<QgsPalLayerSettings::Property, QgsPropertyOverrideButton *> mButtons;

private slots:

void updateProperty();
void initCalloutWidgets();
void updateCalloutWidget( QgsCallout *callout );

Expand Down

0 comments on commit a85d4d1

Please sign in to comment.