From 8575f95c897bcaeb961bfd7209160ab43498c64b Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 5 Jul 2019 11:50:07 +1000 Subject: [PATCH] Use a registry for callouts --- .../auto_generated/callouts/qgscallout.sip.in | 11 +- .../callouts/qgscalloutsregistry.sip.in | 17 ++- src/core/callouts/qgscallout.cpp | 10 +- src/core/callouts/qgscallout.h | 22 ++- src/core/callouts/qgscalloutsregistry.cpp | 19 ++- src/core/callouts/qgscalloutsregistry.h | 25 ++-- src/gui/callouts/qgscalloutwidget.cpp | 131 ++++++++++++++++++ src/gui/callouts/qgscalloutwidget.h | 108 +++++++++++++++ src/gui/qgslabelinggui.cpp | 27 +++- src/gui/qgstextformatwidget.cpp | 3 +- src/ui/qgstextformatwidgetbase.ui | 18 ++- 11 files changed, 347 insertions(+), 44 deletions(-) create mode 100644 src/gui/callouts/qgscalloutwidget.cpp create mode 100644 src/gui/callouts/qgscalloutwidget.h diff --git a/python/core/auto_generated/callouts/qgscallout.sip.in b/python/core/auto_generated/callouts/qgscallout.sip.in index 78beaf08739..aadf912faa7 100644 --- a/python/core/auto_generated/callouts/qgscallout.sip.in +++ b/python/core/auto_generated/callouts/qgscallout.sip.in @@ -195,7 +195,8 @@ A simple direct line callout style. public: QgsSimpleLineCallout(); - QgsSimpleLineCallout( const QgsSimpleLineCallout &other ); + ~QgsSimpleLineCallout(); + static QgsCallout *create( const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext &context = QgsReadWriteContext() ) /Factory/; %Docstring @@ -227,6 +228,9 @@ QgsSimpleLineCallout.properties() ). virtual void draw( QgsRenderContext &context, QRectF rect, const double angle, const QgsGeometry &anchor ); + private: + QgsSimpleLineCallout( const QgsSimpleLineCallout &other ); + QgsSimpleLineCallout &operator=( const QgsSimpleLineCallout & ); }; @@ -239,7 +243,7 @@ class QgsManhattanLineCallout : QgsSimpleLineCallout public: QgsManhattanLineCallout(); - QgsManhattanLineCallout( const QgsManhattanLineCallout &other ); + static QgsCallout *create( const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext &context = QgsReadWriteContext() ) /Factory/; %Docstring @@ -257,6 +261,9 @@ QgsManhattanLineCallout.properties() ). virtual void draw( QgsRenderContext &context, QRectF rect, const double angle, const QgsGeometry &anchor ); + private: + QgsManhattanLineCallout( const QgsManhattanLineCallout &other ); + QgsManhattanLineCallout &operator=( const QgsManhattanLineCallout & ); }; diff --git a/python/core/auto_generated/callouts/qgscalloutsregistry.sip.in b/python/core/auto_generated/callouts/qgscalloutsregistry.sip.in index 7d5aac62fc1..f887abf2969 100644 --- a/python/core/auto_generated/callouts/qgscalloutsregistry.sip.in +++ b/python/core/auto_generated/callouts/qgscalloutsregistry.sip.in @@ -45,7 +45,7 @@ Returns a friendly display name of the callout type. This value is translated. .. seealso:: :py:func:`name` %End - virtual QgsCallout *createCallout( const QVariantMap &properties, const QgsReadWriteContext& context ) = 0 /Factory/; + virtual QgsCallout *createCallout( const QVariantMap &properties, const QgsReadWriteContext &context ) = 0 /Factory/; %Docstring Create a callout of this type given the map of ``properties``. @@ -79,7 +79,7 @@ Convenience metadata class that uses static functions to create callouts and the - virtual QgsCallout * createCallout(const QVariantMap &properties, const QgsReadWriteContext& context ) /Factory/; + virtual QgsCallout *createCallout( const QVariantMap &properties, const QgsReadWriteContext &context ) /Factory/; virtual QgsCalloutWidget *createCalloutWidget( QgsVectorLayer *vl ) /Factory/; @@ -111,7 +111,7 @@ QgsCalloutRegistry is not usually directly created, but rather accessed through ~QgsCalloutRegistry(); - QgsCalloutAbstractMetadata *calloutMetadata( const QString &type) const; + QgsCalloutAbstractMetadata *calloutMetadata( const QString &type ) const; %Docstring Returns the metadata for specified the specified callout ``type``. Returns ``None`` if no matching callout style was found. %End @@ -120,21 +120,26 @@ Returns the metadata for specified the specified callout ``type``. Returns ``Non %Docstring Registers a new callout type. -Owership of ``metadata`` is transferred to the registry. +Ownership of ``metadata`` is transferred to the registry. %End - QgsCallout *createCallout( const QString &type, const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext& context = QgsReadWriteContext() ) const /Factory/; + QgsCallout *createCallout( const QString &type, const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext &context = QgsReadWriteContext() ) const /Factory/; %Docstring Creates a new instance of a callout, given the callout ``type`` and ``properties``. The caller takes ownership of the callout. %End - QgsCallout* createCallout( const QString& type, const QDomElement &element, const QgsReadWriteContext &context ) const /Factory/; + QgsCallout *createCallout( const QString &type, const QDomElement &element, const QgsReadWriteContext &context ) const /Factory/; %Docstring Creates a new instance of a callout of the specified ``type``, using the properties from a DOM ``element``. The caller takes ownership of the callout. +%End + + QStringList calloutTypes() const; +%Docstring +Returns a list of all available callout types. %End static QgsCallout *defaultCallout() /Factory/; diff --git a/src/core/callouts/qgscallout.cpp b/src/core/callouts/qgscallout.cpp index e1e50c3cf91..ec74ef35ed6 100644 --- a/src/core/callouts/qgscallout.cpp +++ b/src/core/callouts/qgscallout.cpp @@ -116,6 +116,8 @@ QgsSimpleLineCallout::QgsSimpleLineCallout() } +QgsSimpleLineCallout::~QgsSimpleLineCallout() = default; + QgsSimpleLineCallout::QgsSimpleLineCallout( const QgsSimpleLineCallout &other ) : QgsCallout( other ) , mLineSymbol( other.mLineSymbol ? other.mLineSymbol->clone() : nullptr ) @@ -123,11 +125,6 @@ QgsSimpleLineCallout::QgsSimpleLineCallout( const QgsSimpleLineCallout &other ) } -QgsSimpleLineCallout &QgsSimpleLineCallout::operator=( const QgsSimpleLineCallout &other ) -{ - mLineSymbol.reset( other.mLineSymbol ? other.mLineSymbol->clone() : nullptr ); -} - QgsCallout *QgsSimpleLineCallout::create( const QVariantMap &properties, const QgsReadWriteContext &context ) { std::unique_ptr< QgsSimpleLineCallout > callout = qgis::make_unique< QgsSimpleLineCallout >(); @@ -250,9 +247,6 @@ QgsManhattanLineCallout::QgsManhattanLineCallout( const QgsManhattanLineCallout } -QgsManhattanLineCallout &QgsManhattanLineCallout::operator=( const QgsManhattanLineCallout &other ) -{ -} QgsCallout *QgsManhattanLineCallout::create( const QVariantMap &properties, const QgsReadWriteContext &context ) { diff --git a/src/core/callouts/qgscallout.h b/src/core/callouts/qgscallout.h index e0bebe76c2f..c73c165307f 100644 --- a/src/core/callouts/qgscallout.h +++ b/src/core/callouts/qgscallout.h @@ -29,6 +29,7 @@ class QgsLineSymbol; class QgsGeometry; class QgsRenderContext; +class QgsCalloutWidget; //stop sip breaking /** * \ingroup core @@ -201,8 +202,12 @@ class CORE_EXPORT QgsSimpleLineCallout : public QgsCallout public: QgsSimpleLineCallout(); + ~QgsSimpleLineCallout() override; + +#ifndef SIP_RUN QgsSimpleLineCallout( const QgsSimpleLineCallout &other ); - QgsSimpleLineCallout &operator=( const QgsSimpleLineCallout & ); + QgsSimpleLineCallout &operator=( const QgsSimpleLineCallout & ) = delete; +#endif /** * Creates a new QgsSimpleLineCallout, using the settings @@ -228,6 +233,11 @@ class CORE_EXPORT QgsSimpleLineCallout : public QgsCallout private: +#ifdef SIP_RUN + QgsSimpleLineCallout( const QgsSimpleLineCallout &other ); + QgsSimpleLineCallout &operator=( const QgsSimpleLineCallout & ); +#endif + std::unique_ptr< QgsLineSymbol > mLineSymbol; }; @@ -237,8 +247,11 @@ class CORE_EXPORT QgsManhattanLineCallout : public QgsSimpleLineCallout public: QgsManhattanLineCallout(); + +#ifndef SIP_RUN QgsManhattanLineCallout( const QgsManhattanLineCallout &other ); - QgsManhattanLineCallout &operator=( const QgsManhattanLineCallout & ); + QgsManhattanLineCallout &operator=( const QgsManhattanLineCallout & ) = delete; +#endif /** * Creates a new QgsManhattanLineCallout, using the settings @@ -253,6 +266,11 @@ class CORE_EXPORT QgsManhattanLineCallout : public QgsSimpleLineCallout protected: void draw( QgsRenderContext &context, QRectF rect, const double angle, const QgsGeometry &anchor ) override; + private: +#ifdef SIP_RUN + QgsManhattanLineCallout( const QgsManhattanLineCallout &other ); + QgsManhattanLineCallout &operator=( const QgsManhattanLineCallout & ); +#endif }; diff --git a/src/core/callouts/qgscalloutsregistry.cpp b/src/core/callouts/qgscalloutsregistry.cpp index 6368f83e2e5..aa9d0370acf 100644 --- a/src/core/callouts/qgscalloutsregistry.cpp +++ b/src/core/callouts/qgscalloutsregistry.cpp @@ -21,7 +21,7 @@ // QgsCalloutAbstractMetadata // -QgsCalloutWidget* QgsCalloutAbstractMetadata::createCalloutWidget(QgsVectorLayer*) +QgsCalloutWidget *QgsCalloutAbstractMetadata::createCalloutWidget( QgsVectorLayer * ) { return nullptr; } @@ -30,12 +30,12 @@ QgsCalloutWidget* QgsCalloutAbstractMetadata::createCalloutWidget(QgsVectorLayer // QgsCalloutMetadata // -QgsCallout* QgsCalloutMetadata::createCallout(const QVariantMap& properties, const QgsReadWriteContext& context) +QgsCallout *QgsCalloutMetadata::createCallout( const QVariantMap &properties, const QgsReadWriteContext &context ) { return mCreateFunc ? mCreateFunc( properties, context ) : nullptr; } -QgsCalloutWidget* QgsCalloutMetadata::createCalloutWidget(QgsVectorLayer* vl) +QgsCalloutWidget *QgsCalloutMetadata::createCalloutWidget( QgsVectorLayer *vl ) { return mWidgetFunc ? mWidgetFunc( vl ) : nullptr; } @@ -48,8 +48,8 @@ QgsCalloutWidget* QgsCalloutMetadata::createCalloutWidget(QgsVectorLayer* vl) QgsCalloutRegistry::QgsCalloutRegistry() { // init registry with known callouts - addCalloutType( new QgsCalloutMetadata( QStringLiteral( "SimpleLine" ), QObject::tr( "Simple lines" ), QgsSimpleLineCallout::create ) ); - addCalloutType( new QgsCalloutMetadata( QStringLiteral( "ManhattanLine" ), QObject::tr( "Manhattan lines" ), QgsManhattanLineCallout::create ) ); + addCalloutType( new QgsCalloutMetadata( QStringLiteral( "simple" ), QObject::tr( "Simple lines" ), QgsSimpleLineCallout::create ) ); + addCalloutType( new QgsCalloutMetadata( QStringLiteral( "manhattan" ), QObject::tr( "Manhattan lines" ), QgsManhattanLineCallout::create ) ); } QgsCalloutRegistry::~QgsCalloutRegistry() @@ -66,12 +66,17 @@ bool QgsCalloutRegistry::addCalloutType( QgsCalloutAbstractMetadata *metadata ) return true; } -QgsCallout* QgsCalloutRegistry::createCallout(const QString& name, const QDomElement& element, const QgsReadWriteContext& context) const +QgsCallout *QgsCalloutRegistry::createCallout( const QString &name, const QDomElement &element, const QgsReadWriteContext &context ) const { const QVariantMap props = QgsXmlUtils::readVariant( element.firstChildElement() ).toMap(); return createCallout( name, props, context ); } +QStringList QgsCalloutRegistry::calloutTypes() const +{ + return mMetadata.keys(); +} + QgsCalloutAbstractMetadata *QgsCalloutRegistry::calloutMetadata( const QString &name ) const { return mMetadata.value( name ); @@ -82,7 +87,7 @@ QgsCallout *QgsCalloutRegistry::defaultCallout() return new QgsManhattanLineCallout(); } -QgsCallout *QgsCalloutRegistry::createCallout( const QString &name, const QVariantMap &properties, const QgsReadWriteContext& context ) const +QgsCallout *QgsCalloutRegistry::createCallout( const QString &name, const QVariantMap &properties, const QgsReadWriteContext &context ) const { if ( !mMetadata.contains( name ) ) return nullptr; diff --git a/src/core/callouts/qgscalloutsregistry.h b/src/core/callouts/qgscalloutsregistry.h index 854f2b4cc32..b0e60dd63b6 100644 --- a/src/core/callouts/qgscalloutsregistry.h +++ b/src/core/callouts/qgscalloutsregistry.h @@ -62,7 +62,7 @@ class CORE_EXPORT QgsCalloutAbstractMetadata * * Ownership of the callout is transferred to the caller. */ - virtual QgsCallout *createCallout( const QVariantMap &properties, const QgsReadWriteContext& context ) = 0 SIP_FACTORY; + virtual QgsCallout *createCallout( const QVariantMap &properties, const QgsReadWriteContext &context ) = 0 SIP_FACTORY; /** * Creates a widget for configuring callouts of this type. Can return NULLPTR if there's no GUI required. @@ -76,7 +76,7 @@ class CORE_EXPORT QgsCalloutAbstractMetadata QString mVisibleName; }; -typedef QgsCallout *( *QgsCalloutCreateFunc )( const QVariantMap &, const QgsReadWriteContext& ) SIP_SKIP; +typedef QgsCallout *( *QgsCalloutCreateFunc )( const QVariantMap &, const QgsReadWriteContext & ) SIP_SKIP; typedef QgsCalloutWidget *( *QgsCalloutWidgetFunc )( QgsVectorLayer * ) SIP_SKIP; /** @@ -90,9 +90,9 @@ class CORE_EXPORT QgsCalloutMetadata : public QgsCalloutAbstractMetadata //! \note not available in Python bindings QgsCalloutMetadata( const QString &name, const QString &visibleName, - QgsCalloutCreateFunc pfCreate, - QgsCalloutWidgetFunc pfWidget = nullptr ) SIP_SKIP - : QgsCalloutAbstractMetadata( name, visibleName ) + QgsCalloutCreateFunc pfCreate, + QgsCalloutWidgetFunc pfWidget = nullptr ) SIP_SKIP + : QgsCalloutAbstractMetadata( name, visibleName ) , mCreateFunc( pfCreate ) , mWidgetFunc( pfWidget ) {} @@ -105,7 +105,7 @@ class CORE_EXPORT QgsCalloutMetadata : public QgsCalloutAbstractMetadata //! \note not available in Python bindings void setWidgetFunction( QgsCalloutWidgetFunc f ) { mWidgetFunc = f; } SIP_SKIP - QgsCallout * createCallout(const QVariantMap &properties, const QgsReadWriteContext& context ) override SIP_FACTORY; + QgsCallout *createCallout( const QVariantMap &properties, const QgsReadWriteContext &context ) override SIP_FACTORY; QgsCalloutWidget *createCalloutWidget( QgsVectorLayer *vl ) override SIP_FACTORY; protected: @@ -143,12 +143,12 @@ class CORE_EXPORT QgsCalloutRegistry /** * Returns the metadata for specified the specified callout \a type. Returns NULLPTR if no matching callout style was found. */ - QgsCalloutAbstractMetadata *calloutMetadata( const QString &type) const; + QgsCalloutAbstractMetadata *calloutMetadata( const QString &type ) const; /** * Registers a new callout type. * - * Owership of \a metadata is transferred to the registry. + * Ownership of \a metadata is transferred to the registry. */ bool addCalloutType( QgsCalloutAbstractMetadata *metadata SIP_TRANSFER ); @@ -157,14 +157,19 @@ class CORE_EXPORT QgsCalloutRegistry * * The caller takes ownership of the callout. */ - QgsCallout *createCallout( const QString &type, const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext& context = QgsReadWriteContext() ) const SIP_FACTORY; + QgsCallout *createCallout( const QString &type, const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext &context = QgsReadWriteContext() ) const SIP_FACTORY; /** * Creates a new instance of a callout of the specified \a type, using the properties from a DOM \a element. * * The caller takes ownership of the callout. */ - QgsCallout* createCallout( const QString& type, const QDomElement &element, const QgsReadWriteContext &context ) const SIP_FACTORY; + QgsCallout *createCallout( const QString &type, const QDomElement &element, const QgsReadWriteContext &context ) const SIP_FACTORY; + + /** + * Returns a list of all available callout types. + */ + QStringList calloutTypes() const; /** * Create a new instance of a callout with default settings. diff --git a/src/gui/callouts/qgscalloutwidget.cpp b/src/gui/callouts/qgscalloutwidget.cpp new file mode 100644 index 00000000000..ae7ff9cd0f0 --- /dev/null +++ b/src/gui/callouts/qgscalloutwidget.cpp @@ -0,0 +1,131 @@ +/*************************************************************************** + qgscalloutwidget.cpp + --------------------- + begin : July 2019 + copyright : (C) 2019 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 "qgscalloutwidget.h" +#include "qgsvectorlayer.h" +#include "qgsexpressioncontextutils.h" +#include "qgsunitselectionwidget.h" +#include "qgscallout.h" +#include "qgsnewauxiliaryfielddialog.h" +#include "qgsnewauxiliarylayerdialog.h" +#include "qgsauxiliarystorage.h" + +QgsExpressionContext QgsCalloutWidget::createExpressionContext() const +{ + if ( mContext.expressionContext() ) + return *mContext.expressionContext(); + + QgsExpressionContext expContext( mContext.globalProjectAtlasMapLayerScopes( vectorLayer() ) ); + + QgsExpressionContextScope *symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr, new QgsExpressionContextScope() ); + if ( const QgsCallout *callout = const_cast< QgsCalloutWidget * >( this )->callout() ) + { + //cheat a bit - set the symbol color variable to match the symbol layer's color (when we should really be using the *symbols* + //color, but that's not accessible here). 99% of the time these will be the same anyway +// symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_COLOR, symbolLayer->color(), true ) ); + } + expContext << symbolScope; + + // additional scopes + const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes(); + for ( const QgsExpressionContextScope &scope : constAdditionalExpressionContextScopes ) + { + expContext.appendScope( new QgsExpressionContextScope( scope ) ); + } + + //TODO - show actual value + expContext.setOriginalValueVariable( QVariant() ); + + expContext.setHighlightedVariables( QStringList() << QgsExpressionContext::EXPR_ORIGINAL_VALUE << QgsExpressionContext::EXPR_SYMBOL_COLOR ); + + return expContext; +} + +void QgsCalloutWidget::setContext( const QgsSymbolWidgetContext &context ) +{ + mContext = context; + const auto unitSelectionWidgets = findChildren(); + for ( QgsUnitSelectionWidget *unitWidget : unitSelectionWidgets ) + { + unitWidget->setMapCanvas( mContext.mapCanvas() ); + } +} + +QgsSymbolWidgetContext QgsCalloutWidget::context() const +{ + return mContext; +} + +void QgsCalloutWidget::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsSymbolLayer::Property key ) +{ +// button->init( key, callout()->dataDefinedProperties(), QgsSymbolLayer::propertyDefinitions(), mVectorLayer, true ); + connect( button, &QgsPropertyOverrideButton::changed, this, &QgsCalloutWidget::updateDataDefinedProperty ); + connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsCalloutWidget::createAuxiliaryField ); + + button->registerExpressionContextGenerator( this ); +} + +void QgsCalloutWidget::createAuxiliaryField() +{ + // try to create an auxiliary layer if not yet created + if ( !mVectorLayer->auxiliaryLayer() ) + { + QgsNewAuxiliaryLayerDialog dlg( mVectorLayer, this ); + dlg.exec(); + } + + // return if still not exists + if ( !mVectorLayer->auxiliaryLayer() ) + return; + + QgsPropertyOverrideButton *button = qobject_cast( sender() ); + QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( button->propertyKey() ); + QgsPropertyDefinition def = QgsSymbolLayer::propertyDefinitions()[key]; + + // create property in auxiliary storage if necessary + if ( !mVectorLayer->auxiliaryLayer()->exists( def ) ) + { + QgsNewAuxiliaryFieldDialog dlg( def, mVectorLayer, true, this ); + if ( dlg.exec() == QDialog::Accepted ) + def = dlg.propertyDefinition(); + } + + // return if still not exist + if ( !mVectorLayer->auxiliaryLayer()->exists( def ) ) + return; + + // 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 ); + +#if 0 + callout()->setDataDefinedProperty( key, button->toProperty() ); +#endif + + emit changed(); +} + +void QgsCalloutWidget::updateDataDefinedProperty() +{ + QgsPropertyOverrideButton *button = qobject_cast( sender() ); + QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( button->propertyKey() ); +#if 0 + callout()->setDataDefinedProperty( key, button->toProperty() ); +#endif + emit changed(); +} diff --git a/src/gui/callouts/qgscalloutwidget.h b/src/gui/callouts/qgscalloutwidget.h new file mode 100644 index 00000000000..6e9696c95c5 --- /dev/null +++ b/src/gui/callouts/qgscalloutwidget.h @@ -0,0 +1,108 @@ +/*************************************************************************** + qgscalloutwidget.h + --------------------- + begin : July 2019 + copyright : (C) 2019 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 QGSCALLOUTWIDGET_H +#define QGSCALLOUTWIDGET_H + +#include "qgspropertyoverridebutton.h" +#include "qgis_sip.h" +#include "qgssymbolwidgetcontext.h" +#include "qgssymbollayer.h" +#include +#include + +class QgsVectorLayer; +class QgsMapCanvas; +class QgsCallout; + +/** + * \ingroup gui + * \class QgsCalloutWidget + */ +class GUI_EXPORT QgsCalloutWidget : public QWidget, protected QgsExpressionContextGenerator +{ + Q_OBJECT + + public: + + /** + * Constructor for QgsCalloutWidget. + * \param vl associated vector layer + * \param parent parent widget + */ + QgsCalloutWidget( QWidget *parent SIP_TRANSFERTHIS, QgsVectorLayer *vl = nullptr ) + : QWidget( parent ) + , mVectorLayer( vl ) + {} + + virtual void setCallout( QgsCallout *callout ) = 0; + virtual QgsCallout *callout() = 0; + + /** + * Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression contexts. + * \param context symbol widget context + * \see context() + * \since QGIS 3.0 + */ + virtual void setContext( const QgsSymbolWidgetContext &context ); + + /** + * Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expression contexts. + * \see setContext() + * \since QGIS 3.0 + */ + QgsSymbolWidgetContext context() const; + + /** + * Returns the vector layer associated with the widget. + * \since QGIS 2.12 + */ + const QgsVectorLayer *vectorLayer() const { return mVectorLayer; } + + protected: + + /** + * Registers a data defined override button. Handles setting up connections + * for the button and initializing the button to show the correct descriptions + * and help text for the associated property. + * \since QGIS 3.0 + */ + void registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsSymbolLayer::Property key ); + + QgsExpressionContext createExpressionContext() const override; + + private: + QgsVectorLayer *mVectorLayer = nullptr; + + QgsMapCanvas *mMapCanvas = nullptr; + + signals: + + /** + * Should be emitted whenever configuration changes happened on this symbol layer configuration. + * If the subsymbol is changed, symbolChanged() should be emitted instead. + */ + void changed(); + + protected slots: + void updateDataDefinedProperty(); + + private slots: + void createAuxiliaryField(); + + private: + QgsSymbolWidgetContext mContext; +}; + +#endif // QGSCALLOUTWIDGET_H diff --git a/src/gui/qgslabelinggui.cpp b/src/gui/qgslabelinggui.cpp index cfc0f858acb..89be11cb40a 100644 --- a/src/gui/qgslabelinggui.cpp +++ b/src/gui/qgslabelinggui.cpp @@ -26,6 +26,8 @@ #include "qgsexpressionbuilderdialog.h" #include "qgsstylesavedialog.h" #include "qgscallout.h" +#include "qgsapplication.h" +#include "qgscalloutsregistry.h" #include #include @@ -100,6 +102,12 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, mMaxScaleWidget->setMapCanvas( mCanvas ); mMaxScaleWidget->setShowCurrentScaleButton( true ); + const QStringList calloutTypes = QgsApplication::calloutRegistry()->calloutTypes(); + for ( const QString &type : calloutTypes ) + { + mCalloutStyleComboBox->addItem( QgsApplication::calloutRegistry()->calloutMetadata( type )->visibleName(), type ); + } + mGeometryGeneratorWarningLabel->setStyleSheet( QStringLiteral( "color: #FFC107;" ) ); mGeometryGeneratorWarningLabel->setTextInteractionFlags( Qt::TextBrowserInteraction ); connect( mGeometryGeneratorWarningLabel, &QLabel::linkActivated, this, [this]( const QString & link ) @@ -278,8 +286,17 @@ void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer ) // callout settings, to move to custom widget when multiple styles exist mCalloutLineStyleButton->setLayer( mLayer ); if ( mSettings.callout() ) + { mCalloutLineStyleButton->setSymbol( static_cast< QgsSimpleLineCallout * >( mSettings.callout() )->lineSymbol()->clone() ); - mCalloutsDrawCheckBox->setChecked( mSettings.callout()->enabled() ); + whileBlocking( mCalloutsDrawCheckBox )->setChecked( mSettings.callout()->enabled() ); + whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( mSettings.callout()->type() ) ); + } + else + { + std::unique_ptr< QgsCallout > defaultCallout( QgsApplication::calloutRegistry()->defaultCallout() ); + whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( defaultCallout->type() ) ); + whileBlocking( mCalloutsDrawCheckBox )->setChecked( false ); + } updatePlacementWidgets(); updateLinePlacementOptions(); @@ -461,10 +478,12 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings() lyr.setDataDefinedProperties( mDataDefinedProperties ); - // callout settings, to move to custom widget when multiple styles exist - std::unique_ptr< QgsManhattanLineCallout > callout = qgis::make_unique< QgsManhattanLineCallout >(); + // callout settings + const QString calloutType = mCalloutStyleComboBox->currentData().toString(); + std::unique_ptr< QgsCallout > callout( QgsApplication::calloutRegistry()->createCallout( calloutType ) ); callout->setEnabled( mCalloutsDrawCheckBox->isChecked() ); - callout->setLineSymbol( mCalloutLineStyleButton->clonedSymbol< QgsLineSymbol >() ); + // todo - move to custom widget + static_cast< QgsSimpleLineCallout * >( callout.get() )->setLineSymbol( mCalloutLineStyleButton->clonedSymbol< QgsLineSymbol >() ); lyr.setCallout( callout.release() ); return lyr; diff --git a/src/gui/qgstextformatwidget.cpp b/src/gui/qgstextformatwidget.cpp index 93af87ff90f..dca34b28bfc 100644 --- a/src/gui/qgstextformatwidget.cpp +++ b/src/gui/qgstextformatwidget.cpp @@ -547,7 +547,8 @@ void QgsTextFormatWidget::initWidget() << mLinePlacementFlagsDDBtn << mBackgroundSymbolButton << mCalloutLineStyleButton - << mCalloutsDrawCheckBox; + << mCalloutsDrawCheckBox + << mCalloutStyleComboBox; connectValueChanged( widgets, SLOT( updatePreview() ) ); connect( mQuadrantBtnGrp, static_cast( &QButtonGroup::buttonClicked ), this, &QgsTextFormatWidget::updatePreview ); diff --git a/src/ui/qgstextformatwidgetbase.ui b/src/ui/qgstextformatwidgetbase.ui index 38c650c23b3..2e7e03e331d 100644 --- a/src/ui/qgstextformatwidgetbase.ui +++ b/src/ui/qgstextformatwidgetbase.ui @@ -3209,8 +3209,8 @@ font-style: italic; 0 0 - 776 - 435 + 259 + 350 @@ -3715,7 +3715,7 @@ font-style: italic; 0 - + @@ -3728,13 +3728,23 @@ font-style: italic; - + Line style + + + + + + + Style + + +