From 76c12ba94c20a2e93b4db2cad3ecd06a4d4690d1 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 4 Oct 2016 21:31:17 +1000 Subject: [PATCH] Split QgsLabelingGui off into QgsTextFormatWidget New widget allows for setting just the formatting properties of text --- python/gui/gui.sip | 2 + python/gui/qgssubstitutionlistwidget.sip | 73 + python/gui/qgstextformatwidget.sip | 88 ++ src/app/CMakeLists.txt | 2 - src/app/qgslabelinggui.cpp | 1346 +--------------- src/app/qgslabelinggui.h | 101 +- src/gui/CMakeLists.txt | 4 + .../qgssubstitutionlistwidget.cpp | 0 src/{app => gui}/qgssubstitutionlistwidget.h | 9 +- src/gui/qgstextformatwidget.cpp | 1378 +++++++++++++++++ src/gui/qgstextformatwidget.h | 198 +++ ...gguibase.ui => qgstextformatwidgetbase.ui} | 818 +++++----- tests/src/python/CMakeLists.txt | 1 + tests/src/python/test_qgstextformatwidget.py | 189 +++ 14 files changed, 2392 insertions(+), 1817 deletions(-) create mode 100644 python/gui/qgssubstitutionlistwidget.sip create mode 100644 python/gui/qgstextformatwidget.sip rename src/{app => gui}/qgssubstitutionlistwidget.cpp (100%) rename src/{app => gui}/qgssubstitutionlistwidget.h (95%) create mode 100644 src/gui/qgstextformatwidget.cpp create mode 100644 src/gui/qgstextformatwidget.h rename src/ui/{qgslabelingguibase.ui => qgstextformatwidgetbase.ui} (98%) create mode 100644 tests/src/python/test_qgstextformatwidget.py diff --git a/python/gui/gui.sip b/python/gui/gui.sip index ef63cb219e2..db7c97cff9e 100644 --- a/python/gui/gui.sip +++ b/python/gui/gui.sip @@ -156,11 +156,13 @@ %Include qgsslider.sip %Include qgssourceselectdialog.sip %Include qgssublayersdialog.sip +%Include qgssubstitutionlistwidget.sip %Include qgssvgannotationitem.sip %Include qgstablewidgetbase.sip %Include qgstabwidget.sip %Include qgstablewidgetitem.sip %Include qgstextannotationitem.sip +%Include qgstextformatwidget.sip %Include qgstextpreview.sip %Include qgstrackedvectorlayertools.sip %Include qgstreewidgetitem.sip diff --git a/python/gui/qgssubstitutionlistwidget.sip b/python/gui/qgssubstitutionlistwidget.sip new file mode 100644 index 00000000000..083ecf886ae --- /dev/null +++ b/python/gui/qgssubstitutionlistwidget.sip @@ -0,0 +1,73 @@ +/** \class QgsSubstitutionListWidget + * \ingroup gui + * A widget which allows users to specify a list of substitutions to apply to a string, with + * options for exporting and importing substitution lists. + * \note added in QGIS 3.0 + * \see QgsSubstitutionListDialog + */ + +class QgsSubstitutionListWidget : public QgsPanelWidget +{ +%TypeHeaderCode + #include +%End + + public: + + /** Constructor for QgsSubstitutionListWidget. + * @param parent parent widget + */ + QgsSubstitutionListWidget( QWidget* parent /TransferThis/ = nullptr ); + + /** Sets the list of substitutions to show in the widget. + * @param substitutions substitution list + * @see substitutions() + */ + void setSubstitutions( const QgsStringReplacementCollection& substitutions ); + + /** Returns the list of substitutions currently defined by the widget. + * @see setSubstitutions() + */ + QgsStringReplacementCollection substitutions() const; + + signals: + + //! Emitted when the substitution definitions change. + void substitutionsChanged( const QgsStringReplacementCollection& substitutions ); + +}; + + + +/** \class QgsSubstitutionListDialog + * \ingroup gui + * A dialog which allows users to specify a list of substitutions to apply to a string, with + * options for exporting and importing substitution lists. + * \see QgsSubstitutionListWidget +*/ + +class QgsSubstitutionListDialog : public QDialog +{ +%TypeHeaderCode + #include +%End + + public: + + /** Constructor for QgsSubstitutionListDialog. + * @param parent parent widget + */ + QgsSubstitutionListDialog( QWidget* parent /TransferThis/ = nullptr ); + + /** Sets the list of substitutions to show in the dialog. + * @param substitutions substitution list + * @see substitutions() + */ + void setSubstitutions( const QgsStringReplacementCollection& substitutions ); + + /** Returns the list of substitutions currently defined by the dialog. + * @see setSubstitutions() + */ + QgsStringReplacementCollection substitutions() const; + +}; diff --git a/python/gui/qgstextformatwidget.sip b/python/gui/qgstextformatwidget.sip new file mode 100644 index 00000000000..371e0f54255 --- /dev/null +++ b/python/gui/qgstextformatwidget.sip @@ -0,0 +1,88 @@ +/** \class QgsTextFormatWidget + * \ingroup gui + * A widget for customising text formatting settings. + * + * QgsTextFormatWidget provides a widget for controlling the appearance of text rendered + * using QgsTextRenderer. The preview includes all settings contained within + * a QgsTextFormat, including shadow, background and buffer. + * + * Additionally, the widget can handle labeling settings due to the large overlap between + * the text renderer settings and the labeling settings. This mode is possible by + * subclassing QgsTextFormatWidget and calling the protected constructor with a mode + * of Labeling. + * + * @note Added in QGIS 3.0 + */ + +class QgsTextFormatWidget : public QgsPanelWidget +{ +%TypeHeaderCode + #include +%End + + public: + + /** Constructor for QgsTextFormatWidget. + * @param format initial formatting settings to show in widget + * @param mapCanvas associated map canvas + * @param parent parent widget + */ + QgsTextFormatWidget( const QgsTextFormat& format = QgsTextFormat(), QgsMapCanvas* mapCanvas = nullptr, QWidget* parent /TransferThis/ = nullptr ); + + ~QgsTextFormatWidget(); + + /** Returns the current formatting settings defined by the widget. + */ + QgsTextFormat format() const; + + public slots: + + /** Sets whether the widget should be shown in a compact dock mode. + * @param enabled set to true to show in dock mode. + */ + void setDockMode( bool enabled ); + + signals: + + //! Emitted when the text format defined by the widget changes + void widgetChanged(); + + protected: + + //! Widget mode + enum Mode + { + Text, //!< Default mode, show text formatting settings only + Labeling, //!< Show labeling settings in addition to text formatting settings + }; + + /** Constructor for QgsTextFormatWidget. + * @param mapCanvas associated map canvas + * @param parent parent widget + * @param mode widget mode + */ + QgsTextFormatWidget( QgsMapCanvas* mapCanvas, QWidget* parent /TransferThis/, Mode mode ); + + /** Updates the widget's state to reflect the settings in a QgsTextFormat. + * @param format source format + */ + void updateWidgetForFormat( const QgsTextFormat& format ); + + /** Sets the background color for the text preview widget. + * @param color background color + */ + void setPreviewBackground( const QColor& color ); + + /** Controls whether data defined alignment buttons are enabled. + * @param enable set to true to enable alignment controls + */ + void enableDataDefinedAlignment( bool enable ); + + protected slots: + + //! Updates line placement options to reflect current state of widget + void updateLinePlacementOptions(); + + //! Updates label placement options to reflect current state of widget + void updatePlacementWidgets(); +}; diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 14cb52ed6bd..0c185ca4297 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -116,7 +116,6 @@ SET(QGIS_APP_SRCS qgsrelationadddlg.cpp qgsselectbyformdialog.cpp qgsstatisticalsummarydockwidget.cpp - qgssubstitutionlistwidget.cpp qgstextannotationdialog.cpp qgssvgannotationdialog.cpp qgsundowidget.cpp @@ -293,7 +292,6 @@ SET (QGIS_APP_MOC_HDRS qgsselectbyformdialog.h qgssponsors.h qgsstatisticalsummarydockwidget.h - qgssubstitutionlistwidget.h qgssvgannotationdialog.h qgstextannotationdialog.h qgstipgui.h diff --git a/src/app/qgslabelinggui.cpp b/src/app/qgslabelinggui.cpp index b50d0fe3b09..02943242428 100644 --- a/src/app/qgslabelinggui.cpp +++ b/src/app/qgslabelinggui.cpp @@ -16,28 +16,11 @@ ***************************************************************************/ #include "qgslabelinggui.h" - -#include -#include -#include -#include - -#include "qgsdatadefinedbutton.h" -#include "qgsexpressionbuilderdialog.h" -#include "qgsexpression.h" -#include "qgsfontutils.h" #include "qgisapp.h" -#include "qgsproject.h" -#include "qgssvgcache.h" -#include "qgssymbollayerutils.h" -#include "qgscharacterselectdialog.h" -#include "qgssvgselectorwidget.h" +#include "qgsvectorlayer.h" +#include "qgsmapcanvas.h" #include "qgsvectorlayerlabeling.h" -#include "qgslogger.h" -#include "qgssubstitutionlistwidget.h" - -#include -#include +#include "qgsproject.h" QgsExpressionContext QgsLabelingGui::createExpressionContext() const { @@ -60,69 +43,11 @@ QgsExpressionContext QgsLabelingGui::createExpressionContext() const } QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const QgsPalLayerSettings* layerSettings, QWidget* parent ) - : QWidget( parent ) + : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling ) , mLayer( layer ) - , mMapCanvas( mapCanvas ) , mSettings( layerSettings ) , mMode( NoLabels ) - , mCharDlg( nullptr ) - , mQuadrantBtnGrp( nullptr ) - , mDirectSymbBtnGrp( nullptr ) - , mUpsidedownBtnGrp( nullptr ) - , mPlacePointBtnGrp( nullptr ) - , mPlaceLineBtnGrp( nullptr ) - , mPlacePolygonBtnGrp( nullptr ) - , mPreviewSize( 24 ) - , mMinPixelLimit( 0 ) - , mLoadSvgParams( false ) { - setupUi( this ); - - mPreviewScaleComboBox->setMapCanvas( mMapCanvas ); - mPreviewScaleComboBox->setShowCurrentScaleButton( true ); - connect( mPreviewScaleComboBox, SIGNAL( scaleChanged( double ) ), this, SLOT( previewScaleChanged( double ) ) ); - - mFieldExpressionWidget->registerExpressionContextGenerator( this ); - - Q_FOREACH ( QgsUnitSelectionWidget* unitWidget, findChildren() ) - { - unitWidget->setMapCanvas( mMapCanvas ); - } - mFontSizeUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderMapUnits - << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderPixels ); - mBufferUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - mShapeSizeUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - mShapeOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - mShapeRadiusUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits - << QgsUnitTypes::RenderPixels << QgsUnitTypes::RenderPercentage ); - mShapeBorderWidthUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - mShadowOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - mShadowRadiusUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - mPointOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - mLineDistanceUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - mRepeatDistanceUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); - - mFontLineHeightSpinBox->setClearValue( 1.0 ); - mShapeRotationDblSpnBx->setClearValue( 0.0 ); - mShapeOffsetXSpnBx->setClearValue( 0.0 ); - mShapeOffsetYSpnBx->setClearValue( 0.0 ); - mPointOffsetXSpinBox->setClearValue( 0.0 ); - mPointOffsetYSpinBox->setClearValue( 0.0 ); - mPointAngleSpinBox->setClearValue( 0.0 ); - mFontLetterSpacingSpinBox->setClearValue( 0.0 ); - mFontWordSpacingSpinBox->setClearValue( 0.0 ); - mZIndexSpinBox->setClearValue( 0.0 ); - - mObstacleTypeComboBox->addItem( tr( "Over the feature's interior" ), QgsPalLayerSettings::PolygonInterior ); - mObstacleTypeComboBox->addItem( tr( "Over the feature's boundary" ), QgsPalLayerSettings::PolygonBoundary ); - - mOffsetTypeComboBox->addItem( tr( "From point" ), QgsPalLayerSettings::FromPoint ); - mOffsetTypeComboBox->addItem( tr( "From symbol bounds" ), QgsPalLayerSettings::FromSymbolBounds ); - - mCharDlg = new QgsCharacterSelectorDialog( this ); - - mRefFont = lblFontPreview->font(); - // connections for groupboxes with separate activation checkboxes (that need to honor data defined setting) connect( mBufferDrawChkBx, SIGNAL( toggled( bool ) ), this, SLOT( updateUi() ) ); connect( mShapeDrawChkBx, SIGNAL( toggled( bool ) ), this, SLOT( updateUi() ) ); @@ -132,443 +57,9 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, connect( mScaleBasedVisibilityChkBx, SIGNAL( toggled( bool ) ), this, SLOT( updateUi() ) ); connect( mFontLimitPixelChkBox, SIGNAL( toggled( bool ) ), this, SLOT( updateUi() ) ); - // internal connections - connect( mFontTranspSlider, SIGNAL( valueChanged( int ) ), mFontTranspSpinBox, SLOT( setValue( int ) ) ); - connect( mFontTranspSpinBox, SIGNAL( valueChanged( int ) ), mFontTranspSlider, SLOT( setValue( int ) ) ); - connect( mBufferTranspSlider, SIGNAL( valueChanged( int ) ), mBufferTranspSpinBox, SLOT( setValue( int ) ) ); - connect( mBufferTranspSpinBox, SIGNAL( valueChanged( int ) ), mBufferTranspSlider, SLOT( setValue( int ) ) ); - connect( mShapeTranspSlider, SIGNAL( valueChanged( int ) ), mShapeTranspSpinBox, SLOT( setValue( int ) ) ); - connect( mShapeTranspSpinBox, SIGNAL( valueChanged( int ) ), mShapeTranspSlider, SLOT( setValue( int ) ) ); - connect( mShadowOffsetAngleDial, SIGNAL( valueChanged( int ) ), mShadowOffsetAngleSpnBx, SLOT( setValue( int ) ) ); - connect( mShadowOffsetAngleSpnBx, SIGNAL( valueChanged( int ) ), mShadowOffsetAngleDial, SLOT( setValue( int ) ) ); - connect( mShadowTranspSlider, SIGNAL( valueChanged( int ) ), mShadowTranspSpnBx, SLOT( setValue( int ) ) ); - connect( mShadowTranspSpnBx, SIGNAL( valueChanged( int ) ), mShadowTranspSlider, SLOT( setValue( int ) ) ); - connect( mLimitLabelChkBox, SIGNAL( toggled( bool ) ), mLimitLabelSpinBox, SLOT( setEnabled( bool ) ) ); - connect( mCheckBoxSubstituteText, SIGNAL( toggled( bool ) ), mToolButtonConfigureSubstitutes, SLOT( setEnabled( bool ) ) ); + mFieldExpressionWidget->registerExpressionContextGenerator( this ); - //connections to prevent users removing all line placement positions - connect( chkLineAbove, SIGNAL( toggled( bool ) ), this, SLOT( updateLinePlacementOptions() ) ); - connect( chkLineBelow, SIGNAL( toggled( bool ) ), this, SLOT( updateLinePlacementOptions() ) ); - connect( chkLineOn, SIGNAL( toggled( bool ) ), this, SLOT( updateLinePlacementOptions() ) ); - - populateFontCapitalsComboBox(); - - // color buttons - mPreviewBackgroundBtn->setColorDialogTitle( tr( "Select fill color" ) ); - mPreviewBackgroundBtn->setContext( "labelling" ); - btnTextColor->setColorDialogTitle( tr( "Select text color" ) ); - btnTextColor->setContext( "labelling" ); - btnTextColor->setDefaultColor( Qt::black ); - btnBufferColor->setColorDialogTitle( tr( "Select buffer color" ) ); - btnBufferColor->setContext( "labelling" ); - btnBufferColor->setDefaultColor( Qt::white ); - mShapeBorderColorBtn->setColorDialogTitle( tr( "Select border color" ) ); - mShapeBorderColorBtn->setContext( "labelling" ); - mShapeFillColorBtn->setColorDialogTitle( tr( "Select fill color" ) ); - mShapeFillColorBtn->setContext( "labelling" ); - mShadowColorBtn->setColorDialogTitle( tr( "Select shadow color" ) ); - mShadowColorBtn->setContext( "labelling" ); - mShadowColorBtn->setDefaultColor( Qt::black ); - - // set up quadrant offset button group - mQuadrantBtnGrp = new QButtonGroup( this ); - mQuadrantBtnGrp->addButton( mPointOffsetAboveLeft, ( int )QgsPalLayerSettings::QuadrantAboveLeft ); - mQuadrantBtnGrp->addButton( mPointOffsetAbove, ( int )QgsPalLayerSettings::QuadrantAbove ); - mQuadrantBtnGrp->addButton( mPointOffsetAboveRight, ( int )QgsPalLayerSettings::QuadrantAboveRight ); - mQuadrantBtnGrp->addButton( mPointOffsetLeft, ( int )QgsPalLayerSettings::QuadrantLeft ); - mQuadrantBtnGrp->addButton( mPointOffsetOver, ( int )QgsPalLayerSettings::QuadrantOver ); - mQuadrantBtnGrp->addButton( mPointOffsetRight, ( int )QgsPalLayerSettings::QuadrantRight ); - mQuadrantBtnGrp->addButton( mPointOffsetBelowLeft, ( int )QgsPalLayerSettings::QuadrantBelowLeft ); - mQuadrantBtnGrp->addButton( mPointOffsetBelow, ( int )QgsPalLayerSettings::QuadrantBelow ); - mQuadrantBtnGrp->addButton( mPointOffsetBelowRight, ( int )QgsPalLayerSettings::QuadrantBelowRight ); - mQuadrantBtnGrp->setExclusive( true ); - - // setup direction symbol(s) button group - mDirectSymbBtnGrp = new QButtonGroup( this ); - mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnLR, ( int )QgsPalLayerSettings::SymbolLeftRight ); - mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnAbove, ( int )QgsPalLayerSettings::SymbolAbove ); - mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnBelow, ( int )QgsPalLayerSettings::SymbolBelow ); - mDirectSymbBtnGrp->setExclusive( true ); - - // upside-down labels button group - mUpsidedownBtnGrp = new QButtonGroup( this ); - mUpsidedownBtnGrp->addButton( mUpsidedownRadioOff, ( int )QgsPalLayerSettings::Upright ); - mUpsidedownBtnGrp->addButton( mUpsidedownRadioDefined, ( int )QgsPalLayerSettings::ShowDefined ); - mUpsidedownBtnGrp->addButton( mUpsidedownRadioAll, ( int )QgsPalLayerSettings::ShowAll ); - mUpsidedownBtnGrp->setExclusive( true ); - - //mShapeCollisionsChkBx->setVisible( false ); // until implemented - - // post updatePlacementWidgets() connections - connect( chkLineAbove, SIGNAL( toggled( bool ) ), this, SLOT( updatePlacementWidgets() ) ); - connect( chkLineBelow, SIGNAL( toggled( bool ) ), this, SLOT( updatePlacementWidgets() ) ); - - // setup point placement button group - mPlacePointBtnGrp = new QButtonGroup( this ); - mPlacePointBtnGrp->addButton( radPredefinedOrder, ( int )QgsPalLayerSettings::OrderedPositionsAroundPoint ); - mPlacePointBtnGrp->addButton( radAroundPoint, ( int )QgsPalLayerSettings::AroundPoint ); - mPlacePointBtnGrp->addButton( radOverPoint, ( int )QgsPalLayerSettings::OverPoint ); - mPlacePointBtnGrp->setExclusive( true ); - connect( mPlacePointBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePlacementWidgets() ) ); - - // setup line placement button group (assigned enum id currently unused) - mPlaceLineBtnGrp = new QButtonGroup( this ); - mPlaceLineBtnGrp->addButton( radLineParallel, ( int )QgsPalLayerSettings::Line ); - mPlaceLineBtnGrp->addButton( radLineCurved, ( int )QgsPalLayerSettings::Curved ); - mPlaceLineBtnGrp->addButton( radLineHorizontal, ( int )QgsPalLayerSettings::Horizontal ); - mPlaceLineBtnGrp->setExclusive( true ); - connect( mPlaceLineBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePlacementWidgets() ) ); - - // setup polygon placement button group (assigned enum id currently unused) - mPlacePolygonBtnGrp = new QButtonGroup( this ); - mPlacePolygonBtnGrp->addButton( radOverCentroid, ( int )QgsPalLayerSettings::OverPoint ); - mPlacePolygonBtnGrp->addButton( radAroundCentroid, ( int )QgsPalLayerSettings::AroundPoint ); - mPlacePolygonBtnGrp->addButton( radPolygonHorizontal, ( int )QgsPalLayerSettings::Horizontal ); - mPlacePolygonBtnGrp->addButton( radPolygonFree, ( int )QgsPalLayerSettings::Free ); - mPlacePolygonBtnGrp->addButton( radPolygonPerimeter, ( int )QgsPalLayerSettings::Line ); - mPlacePolygonBtnGrp->addButton( radPolygonPerimeterCurved, ( int )QgsPalLayerSettings::PerimeterCurved ); - mPlacePolygonBtnGrp->setExclusive( true ); - connect( mPlacePolygonBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePlacementWidgets() ) ); - - // TODO: is this necessary? maybe just use the data defined-only rotation? - mPointAngleDDBtn->setVisible( false ); - - // Global settings group for groupboxes' saved/retored collapsed state - // maintains state across different dialogs - Q_FOREACH ( QgsCollapsibleGroupBox *grpbox, findChildren() ) - { - grpbox->setSettingGroup( QString( "mAdvLabelingDlg" ) ); - } - - connect( groupBox_mPreview, - SIGNAL( collapsedStateChanged( bool ) ), - this, - SLOT( collapseSample( bool ) ) ); - - // get rid of annoying outer focus rect on Mac - mLabelingOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect, false ); - - QSettings settings; - - // reset horiz strech of left side of options splitter (set to 1 for previewing in Qt Designer) - QSizePolicy policy( mLabelingOptionsListFrame->sizePolicy() ); - policy.setHorizontalStretch( 0 ); - mLabelingOptionsListFrame->setSizePolicy( policy ); - if ( !settings.contains( QString( "/Windows/Labeling/OptionsSplitState" ) ) ) - { - // set left list widget width on intial showing - QList splitsizes; - splitsizes << 115; - mLabelingOptionsSplitter->setSizes( splitsizes ); - } - - // set up reverse connection from stack to list - connect( mLabelStackedWidget, SIGNAL( currentChanged( int ) ), this, SLOT( optionsStackedWidget_CurrentChanged( int ) ) ); - - // restore dialog, splitters and current tab - mFontPreviewSplitter->restoreState( settings.value( QString( "/Windows/Labeling/FontPreviewSplitState" ) ).toByteArray() ); - mLabelingOptionsSplitter->restoreState( settings.value( QString( "/Windows/Labeling/OptionsSplitState" ) ).toByteArray() ); - - mLabelingOptionsListWidget->setCurrentRow( settings.value( QString( "/Windows/Labeling/Tab" ), 0 ).toInt() ); - - setDockMode( false ); - - - QList widgets; - widgets << btnBufferColor - << btnTextColor - << chkLabelPerFeaturePart - << chkLineAbove - << chkLineBelow - << chkLineOn - << chkLineOrientationDependent - << chkMergeLines - << chkPreserveRotation - << comboBlendMode - << comboBufferBlendMode - << mAlwaysShowDDBtn - << mBufferBlendModeDDBtn - << mBufferColorDDBtn - << mBufferDrawChkBx - << mBufferDrawDDBtn - << mBufferJoinStyleComboBox - << mBufferJoinStyleDDBtn - << mBufferSizeDDBtn - << mBufferTranspDDBtn - << mBufferTranspFillChbx - << mBufferTranspSpinBox - << mBufferUnitsDDBtn - << mCentroidDDBtn - << mCentroidInsideCheckBox - << mChkNoObstacle - << mCoordAlignmentHDDBtn - << mCoordAlignmentVDDBtn - << mCoordRotationDDBtn - << mCoordXDDBtn - << mCoordYDDBtn - << mDirectSymbChkBx - << mDirectSymbDDBtn - << mDirectSymbLeftDDBtn - << mDirectSymbLeftLineEdit - << mDirectSymbPlacementDDBtn - << mDirectSymbRevChkBx - << mDirectSymbRevDDBtn - << mDirectSymbRightDDBtn - << mDirectSymbRightLineEdit - << mFitInsidePolygonCheckBox - << mFontBlendModeDDBtn - << mFontBoldDDBtn - << mFontCapitalsComboBox - << mFontCaseDDBtn - << mFontColorDDBtn - << mFontDDBtn - << mFontItalicDDBtn - << mFontLetterSpacingDDBtn - << mFontLetterSpacingSpinBox - << mFontLimitPixelChkBox - << mFontLimitPixelDDBtn - << mFontLineHeightDDBtn - << mFontLineHeightSpinBox - << mFontMaxPixelDDBtn - << mFontMaxPixelSpinBox - << mFontMinPixelDDBtn - << mFontMinPixelSpinBox - << mFontMultiLineAlignComboBox - << mFontMultiLineAlignDDBtn - << mFontSizeDDBtn - << mFontSizeSpinBox - << mFontStrikeoutDDBtn - << mFontStyleComboBox - << mFontStyleDDBtn - << mFontTranspDDBtn - << mFontTranspSpinBox - << mFontUnderlineDDBtn - << mFontUnitsDDBtn - << mFontWordSpacingDDBtn - << mFontWordSpacingSpinBox - << mFormatNumChkBx - << mFormatNumDDBtn - << mFormatNumDecimalsDDBtn - << mFormatNumDecimalsSpnBx - << mFormatNumPlusSignChkBx - << mFormatNumPlusSignDDBtn - << mIsObstacleDDBtn - << mLimitLabelChkBox - << mLimitLabelSpinBox - << mLineDistanceDDBtn - << mLineDistanceSpnBx - << mLineDistanceUnitDDBtn - << mLineDistanceUnitWidget - << mMaxCharAngleDDBtn - << mMaxCharAngleInDSpinBox - << mMaxCharAngleOutDSpinBox - << mMinSizeSpinBox - << mObstacleFactorDDBtn - << mObstacleFactorSlider - << mObstacleTypeComboBox - << mOffsetTypeComboBox - << mPalShowAllLabelsForLayerChkBx - << mPointAngleDDBtn - << mPointAngleSpinBox - << mPointOffsetDDBtn - << mPointOffsetUnitsDDBtn - << mPointOffsetUnitWidget - << mPointOffsetXSpinBox - << mPointOffsetYSpinBox - << mPointPositionOrderDDBtn - << mPointQuadOffsetDDBtn - << mPreviewBackgroundBtn - << mPreviewTextEdit - << mPriorityDDBtn - << mPrioritySlider - << mRepeatDistanceDDBtn - << mRepeatDistanceSpinBox - << mRepeatDistanceUnitDDBtn - << mRepeatDistanceUnitWidget - << mScaleBasedVisibilityChkBx - << mScaleBasedVisibilityDDBtn - << mScaleBasedVisibilityMaxDDBtn - << mScaleBasedVisibilityMaxSpnBx - << mScaleBasedVisibilityMinDDBtn - << mScaleBasedVisibilityMinSpnBx - << mShadowBlendCmbBx - << mShadowBlendDDBtn - << mShadowColorBtn - << mShadowColorDDBtn - << mShadowDrawChkBx - << mShadowDrawDDBtn - << mShadowOffsetAngleDDBtn - << mShadowOffsetAngleSpnBx - << mShadowOffsetDDBtn - << mShadowOffsetGlobalChkBx - << mShadowOffsetSpnBx - << mShadowOffsetUnitsDDBtn - << mShadowOffsetUnitWidget - << mShadowRadiusAlphaChkBx - << mShadowRadiusDDBtn - << mShadowRadiusDblSpnBx - << mShadowRadiusUnitsDDBtn - << mShadowRadiusUnitWidget - << mShadowScaleDDBtn - << mShadowScaleSpnBx - << mShadowTranspDDBtn - << mShadowTranspSpnBx - << mShadowUnderCmbBx - << mShadowUnderDDBtn - << mShapeBlendCmbBx - << mShapeBlendModeDDBtn - << mShapeBorderColorBtn - << mShapeBorderColorDDBtn - << mShapeBorderUnitsDDBtn - << mShapeBorderWidthDDBtn - << mShapeBorderWidthSpnBx - << mShapeBorderWidthUnitWidget - << mShapeDrawChkBx - << mShapeDrawDDBtn - << mShapeFillColorBtn - << mShapeFillColorDDBtn - << mShapeOffsetDDBtn - << mShapeOffsetUnitsDDBtn - << mShapeOffsetXSpnBx - << mShapeOffsetYSpnBx - << mShapeOffsetUnitWidget - << mShapePenStyleCmbBx - << mShapePenStyleDDBtn - << mShapeRadiusDDBtn - << mShapeRadiusUnitsDDBtn - << mShapeRadiusXDbSpnBx - << mShapeRadiusYDbSpnBx - << mShapeRotationCmbBx - << mShapeRotationDDBtn - << mShapeRotationDblSpnBx - << mShapeRotationTypeDDBtn - << mShapeRadiusUnitWidget - << mShapeSVGPathDDBtn - << mShapeSVGPathLineEdit - << mShapeSizeCmbBx - << mShapeSizeTypeDDBtn - << mShapeSizeUnitsDDBtn - << mShapeSizeUnitWidget - << mShapeSizeXDDBtn - << mShapeSizeXSpnBx - << mShapeSizeYDDBtn - << mShapeSizeYSpnBx - << mShapeTranspDDBtn - << mShapeTranspSpinBox - << mShapeTypeCmbBx - << mShapeTypeDDBtn - << mShowLabelDDBtn - << mWrapCharDDBtn - << mZIndexDDBtn - << mZIndexSpinBox - << spinBufferSize - << wrapCharacterEdit - << mCentroidRadioVisible - << mCentroidRadioWhole - << mDirectSymbRadioBtnAbove - << mDirectSymbRadioBtnBelow - << mDirectSymbRadioBtnLR - << mUpsidedownRadioAll - << mUpsidedownRadioDefined - << mUpsidedownRadioOff - << radAroundCentroid - << radAroundPoint - << radLineCurved - << radLineHorizontal - << radLineParallel - << radOverCentroid - << radOverPoint - << radPolygonFree - << radPolygonHorizontal - << radPolygonPerimeter - << radPolygonPerimeterCurved - << radPredefinedOrder - << mFieldExpressionWidget - << mCheckBoxSubstituteText; - connectValueChanged( widgets, SLOT( updatePreview() ) ); - - connect( mQuadrantBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePreview() ) ); - - // set correct initial tab to match displayed setting page - whileBlocking( mOptionsTab )->setCurrentIndex( mLabelStackedWidget->currentIndex() ); - - if ( mMapCanvas ) - { - lblFontPreview->setMapUnits( mMapCanvas->mapSettings().mapUnits() ); - mPreviewScaleComboBox->setScale( 1.0 / mMapCanvas->mapSettings().scale() ); - } -} - -void QgsLabelingGui::setDockMode( bool enabled ) -{ - mOptionsTab->setVisible( enabled ); - mOptionsTab->setTabToolTip( 0, tr( "Text" ) ); - mOptionsTab->setTabToolTip( 1, tr( "Formatting" ) ); - mOptionsTab->setTabToolTip( 2, tr( "Buffer" ) ); - mOptionsTab->setTabToolTip( 3, tr( "Background" ) ); - mOptionsTab->setTabToolTip( 4, tr( "Shadow" ) ); - mOptionsTab->setTabToolTip( 5, tr( "Placement" ) ); - mOptionsTab->setTabToolTip( 6, tr( "Rendering" ) ); - - mLabelingOptionsListFrame->setVisible( !enabled ); - groupBox_mPreview->setVisible( !enabled ); - mDockMode = enabled; -} - -void QgsLabelingGui::connectValueChanged( const QList& widgets, const char *slot ) -{ - Q_FOREACH ( QWidget* widget, widgets ) - { - if ( QgsDataDefinedButton* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( dataDefinedActivated( bool ) ), this, slot ); - connect( w, SIGNAL( dataDefinedChanged( QString ) ), this, slot ); - } - else if ( QgsFieldExpressionWidget* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( fieldChanged( QString ) ), this, slot ); - } - else if ( QgsUnitSelectionWidget* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( changed() ), this, slot ); - } - else if ( QComboBox* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( currentIndexChanged( int ) ), this, slot ); - } - else if ( QSpinBox* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( valueChanged( int ) ), this, slot ); - } - else if ( QDoubleSpinBox* w = qobject_cast( widget ) ) - { - connect( w , SIGNAL( valueChanged( double ) ), this, slot ); - } - else if ( QgsColorButton* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( colorChanged( QColor ) ), this, slot ); - } - else if ( QCheckBox* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( toggled( bool ) ), this, slot ); - } - else if ( QRadioButton* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( toggled( bool ) ), this, slot ); - } - else if ( QLineEdit* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( textEdited( QString ) ), this, slot ); - } - else if ( QSlider* w = qobject_cast( widget ) ) - { - connect( w, SIGNAL( valueChanged( int ) ), this, slot ); - } - else - { - QgsLogger::warning( QString( "Could not create connection for widget %1" ).arg( widget->objectName() ) ); - } - } + setLayer( layer ); } void QgsLabelingGui::setLayer( QgsMapLayer* mapLayer ) @@ -584,12 +75,15 @@ void QgsLabelingGui::setLayer( QgsMapLayer* mapLayer ) } QgsVectorLayer *layer = qobject_cast( mapLayer ); - mLayer = layer ; - init(); -} + mLayer = layer; + + // load labeling settings from layer + QgsPalLayerSettings lyr; + if ( mSettings ) + lyr = *mSettings; + else + lyr.readFromLayer( mLayer ); -void QgsLabelingGui::init() -{ // show/hide options based upon geometry type chkMergeLines->setVisible( mLayer->geometryType() == QgsWkbTypes::LineGeometry ); mDirectSymbolsFrame->setVisible( mLayer->geometryType() == QgsWkbTypes::LineGeometry ); @@ -597,13 +91,12 @@ void QgsLabelingGui::init() mPolygonObstacleTypeFrame->setVisible( mLayer->geometryType() == QgsWkbTypes::PolygonGeometry ); mPolygonFeatureOptionsFrame->setVisible( mLayer->geometryType() == QgsWkbTypes::PolygonGeometry ); - // field combo and expression button mFieldExpressionWidget->setLayer( mLayer ); - QgsDistanceArea myDa; - myDa.setSourceCrs( mLayer->crs().srsid() ); - myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapSettings().hasCrsTransformEnabled() ); - myDa.setEllipsoid( QgsProject::instance()->ellipsoid() ); - mFieldExpressionWidget->setGeomCalculator( myDa ); + QgsDistanceArea da; + da.setSourceCrs( mLayer->crs().srsid() ); + da.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapSettings().hasCrsTransformEnabled() ); + da.setEllipsoid( QgsProject::instance()->ellipsoid() ); + mFieldExpressionWidget->setGeomCalculator( da ); // set placement methods page based on geometry type switch ( mLayer->geometryType() ) @@ -636,24 +129,13 @@ void QgsLabelingGui::init() mFontMultiLineAlignComboBox->removeItem( idx ); } - // load labeling settings from layer - QgsPalLayerSettings lyr; - if ( mSettings ) - lyr = *mSettings; - else - lyr.readFromLayer( mLayer ); - - QgsTextFormat format = lyr.format(); - QgsTextBufferSettings buffer = format.buffer(); - QgsTextBackgroundSettings background = format.background(); - QgsTextShadowSettings shadow = format.shadow(); - - blockInitSignals( true ); - mFieldExpressionWidget->setEnabled( mMode == Labels ); mLabelingFrame->setEnabled( mMode == Labels ); - // set the current field or add the current expression to the bottom of the list + updateWidgetForFormat( lyr.format() ); + + blockInitSignals( true ); + mFieldExpressionWidget->setRow( -1 ); mFieldExpressionWidget->setField( lyr.fieldName ); mCheckBoxSubstituteText->setChecked( lyr.useSubstitutions ); @@ -744,7 +226,6 @@ void QgsLabelingGui::init() mMaxCharAngleOutDSpinBox->setValue( qAbs( lyr.maxCurvedCharAngleOut ) ); wrapCharacterEdit->setText( lyr.wrapChar ); - mFontLineHeightSpinBox->setValue( format.lineHeight() ); mFontMultiLineAlignComboBox->setCurrentIndex(( unsigned int ) lyr.multilineAlign ); chkPreserveRotation->setChecked( lyr.preserveRotation ); @@ -756,17 +237,6 @@ void QgsLabelingGui::init() mScaleBasedVisibilityMinSpnBx->setValue( lyr.scaleMin ); mScaleBasedVisibilityMaxSpnBx->setValue( lyr.scaleMax ); - // buffer - mBufferDrawChkBx->setChecked( buffer.enabled() ); - spinBufferSize->setValue( buffer.size() ); - mBufferUnitWidget->setUnit( buffer.sizeUnit() ); - mBufferUnitWidget->setMapUnitScale( buffer.sizeMapUnitScale() ); - btnBufferColor->setColor( buffer.color() ); - mBufferTranspSpinBox->setValue( 100 - 100 * buffer.opacity() ); - mBufferJoinStyleComboBox->setPenJoinStyle( buffer.joinStyle() ); - mBufferTranspFillChbx->setChecked( buffer.fillBufferInterior() ); - comboBufferBlendMode->setBlendMode( buffer.blendMode() ); - mFormatNumChkBx->setChecked( lyr.formatNumbers ); mFormatNumDecimalsSpnBx->setValue( lyr.decimals ); mFormatNumPlusSignChkBx->setChecked( lyr.plusSign ); @@ -777,96 +247,9 @@ void QgsLabelingGui::init() mMinPixelLimit = lyr.fontMinPixelSize; // ignored after first settings save mFontMinPixelSpinBox->setValue( lyr.fontMinPixelSize == 0 ? 3 : lyr.fontMinPixelSize ); mFontMaxPixelSpinBox->setValue( lyr.fontMaxPixelSize ); - mFontSizeUnitWidget->setUnit( format.sizeUnit() ); - mFontSizeUnitWidget->setMapUnitScale( format.sizeMapUnitScale() ); mZIndexSpinBox->setValue( lyr.zIndex ); - mRefFont = format.font(); - mFontSizeSpinBox->setValue( format.size() ); - btnTextColor->setColor( format.color() ); - mFontTranspSpinBox->setValue( 100 - 100 * format.opacity() ); - comboBlendMode->setBlendMode( format.blendMode() ); - - mFontWordSpacingSpinBox->setValue( format.font().wordSpacing() ); - mFontLetterSpacingSpinBox->setValue( format.font().letterSpacing() ); - - QgsFontUtils::updateFontViaStyle( mRefFont, format.namedStyle() ); - updateFont( mRefFont ); - - // show 'font not found' if substitution has occurred (should come after updateFont()) - mFontMissingLabel->setVisible( !format.fontFound() ); - if ( !format.fontFound() ) - { - QString missingTxt = tr( "%1 not found. Default substituted." ); - QString txtPrepend = tr( "Chosen font" ); - if ( !format.resolvedFontFamily().isEmpty() ) - { - txtPrepend = QString( "'%1'" ).arg( format.resolvedFontFamily() ); - } - mFontMissingLabel->setText( missingTxt.arg( txtPrepend ) ); - - // ensure user is sent to 'Text style' section to see notice - mLabelingOptionsListWidget->setCurrentRow( 0 ); - } - - // shape background - mShapeDrawChkBx->setChecked( background.enabled() ); - mShapeTypeCmbBx->blockSignals( true ); - mShapeTypeCmbBx->setCurrentIndex( background.type() ); - mShapeTypeCmbBx->blockSignals( false ); - mShapeSVGPathLineEdit->setText( background.svgFile() ); - - mShapeSizeCmbBx->setCurrentIndex( background.sizeType() ); - mShapeSizeXSpnBx->setValue( background.size().width() ); - mShapeSizeYSpnBx->setValue( background.size().height() ); - mShapeSizeUnitWidget->setUnit( background.sizeUnit() ); - mShapeSizeUnitWidget->setMapUnitScale( background.sizeMapUnitScale() ); - mShapeRotationCmbBx->setCurrentIndex( background.rotationType() ); - mShapeRotationDblSpnBx->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync ); - mShapeRotationDDBtn->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync ); - mShapeRotationDblSpnBx->setValue( background.rotation() ); - mShapeOffsetXSpnBx->setValue( background.offset().x() ); - mShapeOffsetYSpnBx->setValue( background.offset().y() ); - mShapeOffsetUnitWidget->setUnit( background.offsetUnit() ); - mShapeOffsetUnitWidget->setMapUnitScale( background.offsetMapUnitScale() ); - mShapeRadiusXDbSpnBx->setValue( background.radii().width() ); - mShapeRadiusYDbSpnBx->setValue( background.radii().height() ); - mShapeRadiusUnitWidget->setUnit( background.radiiUnit() ); - mShapeRadiusUnitWidget->setMapUnitScale( background.radiiMapUnitScale() ); - - mShapeFillColorBtn->setColor( background.fillColor() ); - mShapeBorderColorBtn->setColor( background.borderColor() ); - mShapeBorderWidthSpnBx->setValue( background.borderWidth() ); - mShapeBorderWidthUnitWidget->setUnit( background.borderWidthUnit() ); - mShapeBorderWidthUnitWidget->setMapUnitScale( background.borderWidthMapUnitScale() ); - mShapePenStyleCmbBx->setPenJoinStyle( background.joinStyle() ); - - mShapeTranspSpinBox->setValue( 100 - background.opacity() * 100.0 ); - mShapeBlendCmbBx->setBlendMode( background.blendMode() ); - - mLoadSvgParams = false; - on_mShapeTypeCmbBx_currentIndexChanged( background.type() ); // force update of shape background gui - - // drop shadow - mShadowDrawChkBx->setChecked( shadow.enabled() ); - mShadowUnderCmbBx->setCurrentIndex( shadow.shadowPlacement() ); - mShadowOffsetAngleSpnBx->setValue( shadow.offsetAngle() ); - mShadowOffsetSpnBx->setValue( shadow.offsetDistance() ); - mShadowOffsetUnitWidget->setUnit( shadow.offsetUnit() ); - mShadowOffsetUnitWidget->setMapUnitScale( shadow.offsetMapUnitScale() ); - mShadowOffsetGlobalChkBx->setChecked( shadow.offsetGlobal() ); - - mShadowRadiusDblSpnBx->setValue( shadow.blurRadius() ); - mShadowRadiusUnitWidget->setUnit( shadow.blurRadiusUnit() ); - mShadowRadiusUnitWidget->setMapUnitScale( shadow.blurRadiusMapUnitScale() ); - mShadowRadiusAlphaChkBx->setChecked( shadow.blurAlphaOnly() ); - mShadowTranspSpnBx->setValue( 100 - shadow.opacity() * 100.0 ); - mShadowScaleSpnBx->setValue( shadow.scale() ); - - mShadowColorBtn->setColor( shadow.color() ); - mShadowBlendCmbBx->setBlendMode( shadow.blendMode() ); - updatePlacementWidgets(); updateLinePlacementOptions(); @@ -878,18 +261,9 @@ void QgsLabelingGui::init() populateDataDefinedButtons( lyr ); enableDataDefinedAlignment( mCoordXDDBtn->isActive() && mCoordYDDBtn->isActive() ); - updateUi(); // should come after data defined button setup } -QgsLabelingGui::~QgsLabelingGui() -{ - QSettings settings; - settings.setValue( QString( "/Windows/Labeling/FontPreviewSplitState" ), mFontPreviewSplitter->saveState() ); - settings.setValue( QString( "/Windows/Labeling/OptionsSplitState" ), mLabelingOptionsSplitter->saveState() ); - settings.setValue( QString( "/Windows/Labeling/Tab" ), mLabelingOptionsListWidget->currentRow() ); -} - void QgsLabelingGui::blockInitSignals( bool block ) { chkLineAbove->blockSignals( block ); @@ -899,29 +273,6 @@ void QgsLabelingGui::blockInitSignals( bool block ) mPlacePolygonBtnGrp->blockSignals( block ); } - -void QgsLabelingGui::optionsStackedWidget_CurrentChanged( int indx ) -{ - mLabelingOptionsListWidget->blockSignals( true ); - mLabelingOptionsListWidget->setCurrentRow( indx ); - mLabelingOptionsListWidget->blockSignals( false ); -} - -void QgsLabelingGui::collapseSample( bool collapse ) -{ - if ( collapse ) - { - QList splitSizes = mFontPreviewSplitter->sizes(); - if ( splitSizes[0] > groupBox_mPreview->height() ) - { - int delta = splitSizes[0] - groupBox_mPreview->height(); - splitSizes[0] -= delta; - splitSizes[1] += delta; - mFontPreviewSplitter->setSizes( splitSizes ); - } - } -} - void QgsLabelingGui::apply() { writeSettingsToLayer(); @@ -943,7 +294,6 @@ void QgsLabelingGui::writeSettingsToLayer() void QgsLabelingGui::setLabelMode( LabelMode mode ) { mMode = mode; - mFieldExpressionWidget->setEnabled( mMode == Labels ); mLabelingFrame->setEnabled( mMode == Labels ); } @@ -1048,78 +398,7 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings() lyr.useSubstitutions = mCheckBoxSubstituteText->isChecked(); lyr.substitutions = mSubstitutions; - QgsTextFormat format; - format.setColor( btnTextColor->color() ); - format.setFont( mRefFont ); - format.setSize( mFontSizeSpinBox->value() ); - format.setNamedStyle( mFontStyleComboBox->currentText() ); - format.setOpacity( 1.0 - mFontTranspSpinBox->value() / 100.0 ); - format.setBlendMode( comboBlendMode->blendMode() ); - format.setSizeUnit( mFontSizeUnitWidget->unit() ); - format.setSizeMapUnitScale( mFontSizeUnitWidget->getMapUnitScale() ); - format.setLineHeight( mFontLineHeightSpinBox->value() ); - - // buffer - QgsTextBufferSettings buffer; - buffer.setEnabled( mBufferDrawChkBx->isChecked() ); - buffer.setSize( spinBufferSize->value() ); - buffer.setColor( btnBufferColor->color() ); - buffer.setOpacity( 1.0 - mBufferTranspSpinBox->value() / 100.0 ); - buffer.setSizeUnit( mBufferUnitWidget->unit() ); - buffer.setSizeMapUnitScale( mBufferUnitWidget->getMapUnitScale() ); - buffer.setJoinStyle( mBufferJoinStyleComboBox->penJoinStyle() ); - buffer.setFillBufferInterior( mBufferTranspFillChbx->isChecked() ); - buffer.setBlendMode( comboBufferBlendMode->blendMode() ); - format.setBuffer( buffer ); - - // shape background - QgsTextBackgroundSettings background; - background.setEnabled( mShapeDrawChkBx->isChecked() ); - background.setType(( QgsTextBackgroundSettings::ShapeType )mShapeTypeCmbBx->currentIndex() ); - background.setSvgFile( mShapeSVGPathLineEdit->text() ); - background.setSizeType(( QgsTextBackgroundSettings::SizeType )mShapeSizeCmbBx->currentIndex() ); - background.setSize( QSizeF( mShapeSizeXSpnBx->value(), mShapeSizeYSpnBx->value() ) ); - background.setSizeUnit( mShapeSizeUnitWidget->unit() ); - background.setSizeMapUnitScale( mShapeSizeUnitWidget->getMapUnitScale() ); - background.setRotationType(( QgsTextBackgroundSettings::RotationType )( mShapeRotationCmbBx->currentIndex() ) ); - background.setRotation( mShapeRotationDblSpnBx->value() ); - background.setOffset( QPointF( mShapeOffsetXSpnBx->value(), mShapeOffsetYSpnBx->value() ) ); - background.setOffsetUnit( mShapeOffsetUnitWidget->unit() ); - background.setOffsetMapUnitScale( mShapeOffsetUnitWidget->getMapUnitScale() ); - background.setRadii( QSizeF( mShapeRadiusXDbSpnBx->value(), mShapeRadiusYDbSpnBx->value() ) ); - background.setRadiiUnit( mShapeRadiusUnitWidget->unit() ); - background.setRadiiMapUnitScale( mShapeRadiusUnitWidget->getMapUnitScale() ); - - background.setFillColor( mShapeFillColorBtn->color() ); - background.setBorderColor( mShapeBorderColorBtn->color() ); - background.setBorderWidth( mShapeBorderWidthSpnBx->value() ); - background.setBorderWidthUnit( mShapeBorderWidthUnitWidget->unit() ); - background.setBorderWidthMapUnitScale( mShapeBorderWidthUnitWidget->getMapUnitScale() ); - background.setJoinStyle( mShapePenStyleCmbBx->penJoinStyle() ); - background.setOpacity( 1.0 - mShapeTranspSpinBox->value() / 100.0 ); - background.setBlendMode( mShapeBlendCmbBx->blendMode() ); - format.setBackground( background ); - - // drop shadow - QgsTextShadowSettings shadow; - shadow.setEnabled( mShadowDrawChkBx->isChecked() ); - shadow.setShadowPlacement(( QgsTextShadowSettings::ShadowPlacement )mShadowUnderCmbBx->currentIndex() ); - shadow.setOffsetAngle( mShadowOffsetAngleSpnBx->value() ); - shadow.setOffsetDistance( mShadowOffsetSpnBx->value() ); - shadow.setOffsetUnit( mShadowOffsetUnitWidget->unit() ); - shadow.setOffsetMapUnitScale( mShadowOffsetUnitWidget->getMapUnitScale() ); - shadow.setOffsetGlobal( mShadowOffsetGlobalChkBx->isChecked() ); - shadow.setBlurRadius( mShadowRadiusDblSpnBx->value() ); - shadow.setBlurRadiusUnit( mShadowRadiusUnitWidget->unit() ); - shadow.setBlurRadiusMapUnitScale( mShadowRadiusUnitWidget->getMapUnitScale() ); - shadow.setBlurAlphaOnly( mShadowRadiusAlphaChkBx->isChecked() ); - shadow.setOpacity( 1.0 - mShadowTranspSpnBx->value() / 100.0 ); - shadow.setScale( mShadowScaleSpnBx->value() ); - shadow.setColor( mShadowColorBtn->color() ); - shadow.setBlendMode( mShadowBlendCmbBx->blendMode() ); - format.setShadow( shadow ); - - lyr.setFormat( format ); + lyr.setFormat( format() ); // format numbers lyr.formatNumbers = mFormatNumChkBx->isChecked(); @@ -1553,84 +832,6 @@ void QgsLabelingGui::populateDataDefinedButtons( QgsPalLayerSettings& s ) QgsDataDefinedButton::AnyType, QgsDataDefinedButton::doubleDesc() ); } -void QgsLabelingGui::changeTextColor( const QColor &color ) -{ - Q_UNUSED( color ) - updatePreview(); -} - -void QgsLabelingGui::updateFont( const QFont& font ) -{ - // update background reference font - if ( font != mRefFont ) - { - mRefFont = font; - } - - // test if font is actually available - // NOTE: QgsFontUtils::fontMatchOnSystem may fail here, just crosscheck family - mFontMissingLabel->setVisible( !QgsFontUtils::fontFamilyMatchOnSystem( mRefFont.family() ) ); - - mDirectSymbLeftLineEdit->setFont( mRefFont ); - mDirectSymbRightLineEdit->setFont( mRefFont ); - - blockFontChangeSignals( true ); - mFontFamilyCmbBx->setCurrentFont( mRefFont ); - populateFontStyleComboBox(); - int idx = mFontCapitalsComboBox->findData( QVariant(( unsigned int ) mRefFont.capitalization() ) ); - mFontCapitalsComboBox->setCurrentIndex( idx == -1 ? 0 : idx ); - mFontUnderlineBtn->setChecked( mRefFont.underline() ); - mFontStrikethroughBtn->setChecked( mRefFont.strikeOut() ); - blockFontChangeSignals( false ); - - // update font name with font face -// font.setPixelSize( 24 ); - - updatePreview(); -} - -void QgsLabelingGui::blockFontChangeSignals( bool blk ) -{ - mFontFamilyCmbBx->blockSignals( blk ); - mFontStyleComboBox->blockSignals( blk ); - mFontCapitalsComboBox->blockSignals( blk ); - mFontUnderlineBtn->blockSignals( blk ); - mFontStrikethroughBtn->blockSignals( blk ); - mFontWordSpacingSpinBox->blockSignals( blk ); - mFontLetterSpacingSpinBox->blockSignals( blk ); -} - -void QgsLabelingGui::updatePreview() -{ - // In dock mode we don't have a preview we - // just let stuff know we have changed because - // there might be live updates connected. - if ( mLayer && mDockMode ) - { - emit widgetChanged(); - return; - } - - QgsTextFormat format = layerSettings().format(); - - scrollPreview(); - lblFontPreview->setFormat( format ); - QString grpboxtitle; - groupBox_mPreview->setTitle( grpboxtitle ); -} - -void QgsLabelingGui::scrollPreview() -{ - scrollArea_mPreview->ensureVisible( 0, 0, 0, 0 ); -} - -void QgsLabelingGui::setPreviewBackground( const QColor& color ) -{ - scrollArea_mPreview->widget()->setStyleSheet( QString( "background: rgb(%1, %2, %3);" ).arg( QString::number( color.red() ), - QString::number( color.green() ), - QString::number( color.blue() ) ) ); -} - void QgsLabelingGui::syncDefinedCheckboxFrame( QgsDataDefinedButton* ddBtn, QCheckBox* chkBx, QFrame* f ) { if ( ddBtn->isActive() && !chkBx->isChecked() ) @@ -1654,505 +855,6 @@ void QgsLabelingGui::updateUi() syncDefinedCheckboxFrame( mFontLimitPixelDDBtn, mFontLimitPixelChkBox, mFontLimitPixelFrame ); } -void QgsLabelingGui::changeBufferColor( const QColor &color ) -{ - Q_UNUSED( color ) - updatePreview(); -} -void QgsLabelingGui::updatePlacementWidgets() -{ - QWidget* curWdgt = stackedPlacement->currentWidget(); - - bool showLineFrame = false; - bool showCentroidFrame = false; - bool showQuadrantFrame = false; - bool showFixedQuadrantFrame = false; - bool showPlacementPriorityFrame = false; - bool showOffsetTypeFrame = false; - bool showOffsetFrame = false; - bool showDistanceFrame = false; - bool showRotationFrame = false; - bool showMaxCharAngleFrame = false; - - bool enableMultiLinesFrame = true; - - if (( curWdgt == pagePoint && radAroundPoint->isChecked() ) - || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) ) - { - showCentroidFrame = ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ); - showDistanceFrame = true; - //showRotationFrame = true; // TODO: uncomment when supported - if ( curWdgt == pagePoint ) - { - showQuadrantFrame = true; - } - } - else if (( curWdgt == pagePoint && radOverPoint->isChecked() ) - || ( curWdgt == pagePolygon && radOverCentroid->isChecked() ) ) - { - showCentroidFrame = ( curWdgt == pagePolygon && radOverCentroid->isChecked() ); - showQuadrantFrame = true; - showFixedQuadrantFrame = true; - showOffsetFrame = true; - showRotationFrame = true; - } - else if ( curWdgt == pagePoint && radPredefinedOrder->isChecked() ) - { - showDistanceFrame = true; - showPlacementPriorityFrame = true; - showOffsetTypeFrame = true; - } - else if (( curWdgt == pageLine && radLineParallel->isChecked() ) - || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) - || ( curWdgt == pageLine && radLineCurved->isChecked() ) - || ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() ) ) - { - showLineFrame = true; - showDistanceFrame = true; - //showRotationFrame = true; // TODO: uncomment when supported - - bool offline = chkLineAbove->isChecked() || chkLineBelow->isChecked(); - chkLineOrientationDependent->setEnabled( offline ); - mPlacementDistanceFrame->setEnabled( offline ); - - bool isCurved = ( curWdgt == pageLine && radLineCurved->isChecked() ) - || ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() ); - showMaxCharAngleFrame = isCurved; - // TODO: enable mMultiLinesFrame when supported for curved labels - enableMultiLinesFrame = !isCurved; - } - - mPlacementLineFrame->setVisible( showLineFrame ); - mPlacementCentroidFrame->setVisible( showCentroidFrame ); - mPlacementQuadrantFrame->setVisible( showQuadrantFrame ); - mPlacementFixedQuadrantFrame->setVisible( showFixedQuadrantFrame ); - mPlacementCartographicFrame->setVisible( showPlacementPriorityFrame ); - mPlacementOffsetFrame->setVisible( showOffsetFrame ); - mPlacementDistanceFrame->setVisible( showDistanceFrame ); - mPlacementOffsetTypeFrame->setVisible( showOffsetTypeFrame ); - mPlacementRotationFrame->setVisible( showRotationFrame ); - mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon && - ( radPolygonPerimeter->isChecked() || radPolygonPerimeterCurved->isChecked() ) ) ); - mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame ); - - mMultiLinesFrame->setEnabled( enableMultiLinesFrame ); -} - -void QgsLabelingGui::populateFontCapitalsComboBox() -{ - mFontCapitalsComboBox->addItem( tr( "No change" ), QVariant( 0 ) ); - mFontCapitalsComboBox->addItem( tr( "All uppercase" ), QVariant( 1 ) ); - mFontCapitalsComboBox->addItem( tr( "All lowercase" ), QVariant( 2 ) ); - // Small caps doesn't work right with QPainterPath::addText() - // https://bugreports.qt-project.org/browse/QTBUG-13965 -// mFontCapitalsComboBox->addItem( tr( "Small caps" ), QVariant( 3 ) ); - mFontCapitalsComboBox->addItem( tr( "Capitalize first letter" ), QVariant( 4 ) ); -} - -void QgsLabelingGui::populateFontStyleComboBox() -{ - mFontStyleComboBox->clear(); - Q_FOREACH ( const QString &style, mFontDB.styles( mRefFont.family() ) ) - { - mFontStyleComboBox->addItem( style ); - } - - int curIndx = 0; - int stylIndx = mFontStyleComboBox->findText( mFontDB.styleString( mRefFont ) ); - if ( stylIndx > -1 ) - { - curIndx = stylIndx; - } - - mFontStyleComboBox->setCurrentIndex( curIndx ); -} - -void QgsLabelingGui::on_mFontSizeSpinBox_valueChanged( double d ) -{ - mRefFont.setPointSizeF( d ); - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontCapitalsComboBox_currentIndexChanged( int index ) -{ - int capitalsindex = mFontCapitalsComboBox->itemData( index ).toUInt(); - mRefFont.setCapitalization(( QFont::Capitalization ) capitalsindex ); - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontFamilyCmbBx_currentFontChanged( const QFont& f ) -{ - mRefFont.setFamily( f.family() ); - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontStyleComboBox_currentIndexChanged( const QString & text ) -{ - QgsFontUtils::updateFontViaStyle( mRefFont, text ); - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontUnderlineBtn_toggled( bool ckd ) -{ - mRefFont.setUnderline( ckd ); - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontStrikethroughBtn_toggled( bool ckd ) -{ - mRefFont.setStrikeOut( ckd ); - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontWordSpacingSpinBox_valueChanged( double spacing ) -{ - mRefFont.setWordSpacing( spacing ); - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontLetterSpacingSpinBox_valueChanged( double spacing ) -{ - mRefFont.setLetterSpacing( QFont::AbsoluteSpacing, spacing ); - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontSizeUnitWidget_changed() -{ - int index = mFontSizeUnitWidget->getUnit(); - // disable pixel size limiting for labels defined in points - if ( index == 0 ) - { - mFontLimitPixelChkBox->setChecked( false ); - } - else if ( index == 1 && mMinPixelLimit == 0 ) - { - // initial minimum trigger value set, turn on pixel size limiting by default - // for labels defined in map units (ignored after first settings save) - mFontLimitPixelChkBox->setChecked( true ); - } - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mFontMinPixelSpinBox_valueChanged( int px ) -{ - // ensure max font pixel size for map unit labels can't be lower than min - mFontMaxPixelSpinBox->setMinimum( px ); - mFontMaxPixelSpinBox->update(); -} - -void QgsLabelingGui::on_mFontMaxPixelSpinBox_valueChanged( int px ) -{ - // ensure max font pixel size for map unit labels can't be lower than min - if ( px < mFontMinPixelSpinBox->value() ) - { - mFontMaxPixelSpinBox->blockSignals( true ); - mFontMaxPixelSpinBox->setValue( mFontMinPixelSpinBox->value() ); - mFontMaxPixelSpinBox->blockSignals( false ); - } - mFontMaxPixelSpinBox->setMinimum( mFontMinPixelSpinBox->value() ); -} - -void QgsLabelingGui::on_mBufferUnitWidget_changed() -{ - updateFont( mRefFont ); -} - -void QgsLabelingGui::on_mCoordXDDBtn_dataDefinedActivated( bool active ) -{ - if ( !active ) //no data defined alignment without data defined position - { - enableDataDefinedAlignment( false ); - } - else if ( mCoordYDDBtn->isActive() ) - { - enableDataDefinedAlignment( true ); - } -} - -void QgsLabelingGui::on_mCoordYDDBtn_dataDefinedActivated( bool active ) -{ - if ( !active ) //no data defined alignment without data defined position - { - enableDataDefinedAlignment( false ); - } - else if ( mCoordXDDBtn->isActive() ) - { - enableDataDefinedAlignment( true ); - } -} - -void QgsLabelingGui::on_mShapeTypeCmbBx_currentIndexChanged( int index ) -{ - // shape background - bool isRect = (( QgsTextBackgroundSettings::ShapeType )index == QgsTextBackgroundSettings::ShapeRectangle - || ( QgsTextBackgroundSettings::ShapeType )index == QgsTextBackgroundSettings::ShapeSquare ); - bool isSVG = (( QgsTextBackgroundSettings::ShapeType )index == QgsTextBackgroundSettings::ShapeSVG ); - - showBackgroundPenStyle( isRect ); - showBackgroundRadius( isRect ); - - mShapeSVGPathFrame->setVisible( isSVG ); - // symbology SVG renderer only supports size^2 scaling, so we only use the x size spinbox - mShapeSizeYLabel->setVisible( !isSVG ); - mShapeSizeYSpnBx->setVisible( !isSVG ); - mShapeSizeYDDBtn->setVisible( !isSVG ); - mShapeSizeXLabel->setText( tr( "Size%1" ).arg( !isSVG ? tr( " X" ) : "" ) ); - - // SVG parameter setting doesn't support color's alpha component yet - mShapeFillColorBtn->setAllowAlpha( !isSVG ); - mShapeFillColorBtn->setButtonBackground(); - mShapeBorderColorBtn->setAllowAlpha( !isSVG ); - mShapeBorderColorBtn->setButtonBackground(); - - // configure SVG parameter widgets - mShapeSVGParamsBtn->setVisible( isSVG ); - if ( isSVG ) - { - updateSvgWidgets( mShapeSVGPathLineEdit->text() ); - } - else - { - mShapeFillColorLabel->setEnabled( true ); - mShapeFillColorBtn->setEnabled( true ); - mShapeFillColorDDBtn->setEnabled( true ); - mShapeBorderColorLabel->setEnabled( true ); - mShapeBorderColorBtn->setEnabled( true ); - mShapeBorderColorDDBtn->setEnabled( true ); - mShapeBorderWidthLabel->setEnabled( true ); - mShapeBorderWidthSpnBx->setEnabled( true ); - mShapeBorderWidthDDBtn->setEnabled( true ); - } - // TODO: fix overriding SVG symbol's border width units in QgsSvgCache - // currently broken, fall back to symbol units only - mShapeBorderWidthUnitWidget->setVisible( !isSVG ); - mShapeSVGUnitsLabel->setVisible( isSVG ); - mShapeBorderUnitsDDBtn->setEnabled( !isSVG ); -} - -void QgsLabelingGui::on_mShapeSVGPathLineEdit_textChanged( const QString& text ) -{ - updateSvgWidgets( text ); -} - -void QgsLabelingGui::updateLinePlacementOptions() -{ - int numOptionsChecked = ( chkLineAbove->isChecked() ? 1 : 0 ) + - ( chkLineBelow->isChecked() ? 1 : 0 ) + - ( chkLineOn->isChecked() ? 1 : 0 ); - - if ( numOptionsChecked == 1 ) - { - //prevent unchecking last option - chkLineAbove->setEnabled( !chkLineAbove->isChecked() ); - chkLineBelow->setEnabled( !chkLineBelow->isChecked() ); - chkLineOn->setEnabled( !chkLineOn->isChecked() ); - } - else - { - chkLineAbove->setEnabled( true ); - chkLineBelow->setEnabled( true ); - chkLineOn->setEnabled( true ); - } -} - -void QgsLabelingGui::onSubstitutionsChanged( const QgsStringReplacementCollection& substitutions ) -{ - mSubstitutions = substitutions; - emit widgetChanged(); -} - -void QgsLabelingGui::previewScaleChanged( double scale ) -{ - lblFontPreview->setScale( scale ); -} - -void QgsLabelingGui::updateSvgWidgets( const QString& svgPath ) -{ - if ( mShapeSVGPathLineEdit->text() != svgPath ) - { - mShapeSVGPathLineEdit->setText( svgPath ); - } - - QString resolvedPath = QgsSymbolLayerUtils::symbolNameToPath( svgPath ); - bool validSVG = !resolvedPath.isNull(); - - // draw red text for path field if invalid (path can't be resolved) - mShapeSVGPathLineEdit->setStyleSheet( QString( !validSVG ? "QLineEdit{ color: rgb(225, 0, 0); }" : "" ) ); - mShapeSVGPathLineEdit->setToolTip( !validSVG ? tr( "File not found" ) : resolvedPath ); - - QColor fill, outline; - double outlineWidth = 0.0; - bool fillParam = false, outlineParam = false, outlineWidthParam = false; - if ( validSVG ) - { - QgsSvgCache::instance()->containsParams( resolvedPath, fillParam, fill, outlineParam, outline, outlineWidthParam, outlineWidth ); - } - - mShapeSVGParamsBtn->setEnabled( validSVG && ( fillParam || outlineParam || outlineWidthParam ) ); - - mShapeFillColorLabel->setEnabled( validSVG && fillParam ); - mShapeFillColorBtn->setEnabled( validSVG && fillParam ); - mShapeFillColorDDBtn->setEnabled( validSVG && fillParam ); - if ( mLoadSvgParams && validSVG && fillParam ) - mShapeFillColorBtn->setColor( fill ); - - mShapeBorderColorLabel->setEnabled( validSVG && outlineParam ); - mShapeBorderColorBtn->setEnabled( validSVG && outlineParam ); - mShapeBorderColorDDBtn->setEnabled( validSVG && outlineParam ); - if ( mLoadSvgParams && validSVG && outlineParam ) - mShapeBorderColorBtn->setColor( outline ); - - mShapeBorderWidthLabel->setEnabled( validSVG && outlineWidthParam ); - mShapeBorderWidthSpnBx->setEnabled( validSVG && outlineWidthParam ); - mShapeBorderWidthDDBtn->setEnabled( validSVG && outlineWidthParam ); - if ( mLoadSvgParams && validSVG && outlineWidthParam ) - mShapeBorderWidthSpnBx->setValue( outlineWidth ); - - // TODO: fix overriding SVG symbol's border width units in QgsSvgCache - // currently broken, fall back to symbol's - //mShapeBorderWidthUnitWidget->setEnabled( validSVG && outlineWidthParam ); - //mShapeBorderUnitsDDBtn->setEnabled( validSVG && outlineWidthParam ); - mShapeSVGUnitsLabel->setEnabled( validSVG && outlineWidthParam ); -} - -void QgsLabelingGui::on_mShapeSVGSelectorBtn_clicked() -{ - QgsSvgSelectorDialog svgDlg( this ); - svgDlg.setWindowTitle( tr( "Select SVG file" ) ); - svgDlg.svgSelector()->setSvgPath( mShapeSVGPathLineEdit->text().trimmed() ); - - if ( svgDlg.exec() == QDialog::Accepted ) - { - QString svgPath = svgDlg.svgSelector()->currentSvgPath(); - if ( !svgPath.isEmpty() ) - { - mShapeSVGPathLineEdit->setText( svgPath ); - } - } -} - -void QgsLabelingGui::on_mShapeSVGParamsBtn_clicked() -{ - QString svgPath = mShapeSVGPathLineEdit->text(); - mLoadSvgParams = true; - updateSvgWidgets( svgPath ); - mLoadSvgParams = false; -} - -void QgsLabelingGui::on_mShapeRotationCmbBx_currentIndexChanged( int index ) -{ - mShapeRotationDblSpnBx->setEnabled(( QgsTextBackgroundSettings::RotationType )index != QgsTextBackgroundSettings::RotationSync ); - mShapeRotationDDBtn->setEnabled(( QgsTextBackgroundSettings::RotationType )index != QgsTextBackgroundSettings::RotationSync ); -} - -void QgsLabelingGui::on_mPreviewTextEdit_textChanged( const QString & text ) -{ - lblFontPreview->setText( text ); - updatePreview(); -} - -void QgsLabelingGui::on_mPreviewTextBtn_clicked() -{ - mPreviewTextEdit->setText( QString( "Lorem Ipsum" ) ); - updatePreview(); -} - -void QgsLabelingGui::on_mPreviewBackgroundBtn_colorChanged( const QColor &color ) -{ - setPreviewBackground( color ); -} - -void QgsLabelingGui::on_mDirectSymbLeftToolBtn_clicked() -{ - bool gotChar = false; - 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 = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ) ); - - if ( !gotChar ) - return; - - if ( !dirSymb.isNull() ) - mDirectSymbRightLineEdit->setText( QString( dirSymb ) ); -} - -void QgsLabelingGui::on_mChkNoObstacle_toggled( bool active ) -{ - mPolygonObstacleTypeFrame->setEnabled( active ); - mObstaclePriorityFrame->setEnabled( active ); -} - -void QgsLabelingGui::on_chkLineOrientationDependent_toggled( bool active ) -{ - if ( active ) - { - chkLineAbove->setText( tr( "Left of line" ) ); - chkLineBelow->setText( tr( "Right of line" ) ); - } - else - { - chkLineAbove->setText( tr( "Above line" ) ); - chkLineBelow->setText( tr( "Below line" ) ); - } -} - -void QgsLabelingGui::on_mToolButtonConfigureSubstitutes_clicked() -{ - QgsPanelWidget* panel = QgsPanelWidget::findParentPanel( this ); - if ( panel && panel->dockMode() ) - { - QgsSubstitutionListWidget* widget = new QgsSubstitutionListWidget( panel ); - widget->setPanelTitle( tr( "Substitutions" ) ); - widget->setSubstitutions( mSubstitutions ); - connect( widget, SIGNAL( substitutionsChanged( QgsStringReplacementCollection ) ), this, SLOT( onSubstitutionsChanged( QgsStringReplacementCollection ) ) ); - panel->openPanel( widget ); - return; - } - - QgsSubstitutionListDialog dlg( this ); - dlg.setSubstitutions( mSubstitutions ); - if ( dlg.exec() == QDialog::Accepted ) - { - mSubstitutions = dlg.substitutions(); - emit widgetChanged(); - } -} - -void QgsLabelingGui::showBackgroundRadius( bool show ) -{ - mShapeRadiusLabel->setVisible( show ); - mShapeRadiusXDbSpnBx->setVisible( show ); - - mShapeRadiusYDbSpnBx->setVisible( show ); - - mShapeRadiusUnitWidget->setVisible( show ); - - mShapeRadiusDDBtn->setVisible( show ); - mShapeRadiusUnitsDDBtn->setVisible( show ); -} - -void QgsLabelingGui::showBackgroundPenStyle( bool show ) -{ - mShapePenStyleLabel->setVisible( show ); - mShapePenStyleCmbBx->setVisible( show ); - - mShapePenStyleDDBtn->setVisible( show ); -} - -void QgsLabelingGui::enableDataDefinedAlignment( bool enable ) -{ - mCoordAlignmentFrame->setEnabled( enable ); -} diff --git a/src/app/qgslabelinggui.h b/src/app/qgslabelinggui.h index ce7e2856ac9..789c1506290 100644 --- a/src/app/qgslabelinggui.h +++ b/src/app/qgslabelinggui.h @@ -15,26 +15,18 @@ * * ***************************************************************************/ -#ifndef QgsLabelingGUI_H -#define QgsLabelingGUI_H +#ifndef QGSLABELINGGUI_H +#define QGSLABELINGGUI_H -#include -#include -#include -#include "qgsstringutils.h" #include "qgspallabeling.h" +#include "qgstextformatwidget.h" -class QgsVectorLayer; -class QgsMapCanvas; -class QgsCharacterSelectorDialog; - -class APP_EXPORT QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase, private QgsExpressionContextGenerator +class APP_EXPORT QgsLabelingGui : public QgsTextFormatWidget, private QgsExpressionContextGenerator { Q_OBJECT public: QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const QgsPalLayerSettings* settings, QWidget* parent ); - ~QgsLabelingGui(); QgsPalLayerSettings layerSettings(); void writeSettingsToLayer(); @@ -48,111 +40,30 @@ class APP_EXPORT QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase void setLabelMode( LabelMode mode ); - signals: - void widgetChanged(); + void setLayer( QgsMapLayer* layer ); public slots: - void setLayer( QgsMapLayer* layer ); - void setDockMode( bool enabled ); - void connectValueChanged( const QList &widgets, const char* slot ); - void init(); - void collapseSample( bool collapse ); void apply(); - void changeTextColor( const QColor &color ); - void changeBufferColor( const QColor &color ); void updateUi(); - void updatePreview(); - void scrollPreview(); - void updatePlacementWidgets(); - void updateSvgWidgets( const QString& svgPath ); - - void on_mFontSizeSpinBox_valueChanged( double d ); - void on_mFontCapitalsComboBox_currentIndexChanged( int index ); - void on_mFontFamilyCmbBx_currentFontChanged( const QFont& f ); - void on_mFontStyleComboBox_currentIndexChanged( const QString & text ); - void on_mFontUnderlineBtn_toggled( bool ckd ); - void on_mFontStrikethroughBtn_toggled( bool ckd ); - void on_mFontWordSpacingSpinBox_valueChanged( double spacing ); - void on_mFontLetterSpacingSpinBox_valueChanged( double spacing ); - void on_mFontSizeUnitWidget_changed(); - void on_mFontMinPixelSpinBox_valueChanged( int px ); - void on_mFontMaxPixelSpinBox_valueChanged( int px ); - void on_mBufferUnitWidget_changed(); - void on_mCoordXDDBtn_dataDefinedActivated( bool active ); - void on_mCoordYDDBtn_dataDefinedActivated( bool active ); - - void on_mShapeTypeCmbBx_currentIndexChanged( int index ); - void on_mShapeRotationCmbBx_currentIndexChanged( int index ); - void on_mShapeSVGParamsBtn_clicked(); - void on_mShapeSVGSelectorBtn_clicked(); - - void on_mPreviewTextEdit_textChanged( const QString & text ); - void on_mPreviewTextBtn_clicked(); - void on_mPreviewBackgroundBtn_colorChanged( const QColor &color ); - void on_mDirectSymbLeftToolBtn_clicked(); - void on_mDirectSymbRightToolBtn_clicked(); - void on_mChkNoObstacle_toggled( bool active ); - void on_chkLineOrientationDependent_toggled( bool active ); - - void on_mToolButtonConfigureSubstitutes_clicked(); protected: void blockInitSignals( bool block ); - void blockFontChangeSignals( bool blk ); - void setPreviewBackground( const QColor& color ); void syncDefinedCheckboxFrame( QgsDataDefinedButton* ddBtn, QCheckBox* chkBx, QFrame* f ); - void populateFontCapitalsComboBox(); - void populateFontStyleComboBox(); - void populatePlacementMethods(); - void populateFieldNames(); void populateDataDefinedButtons( QgsPalLayerSettings& s ); /** Sets data defined property attribute to map */ void setDataDefinedProperty( const QgsDataDefinedButton* ddBtn, QgsPalLayerSettings::DataDefinedProperties p, QgsPalLayerSettings& lyr ); - void updateFont( const QFont& font ); private: QgsVectorLayer* mLayer; - QgsMapCanvas* mMapCanvas; const QgsPalLayerSettings* mSettings; LabelMode mMode; - QFontDatabase mFontDB; - QgsCharacterSelectorDialog* mCharDlg; - - QButtonGroup* mQuadrantBtnGrp; - QButtonGroup* mDirectSymbBtnGrp; - QButtonGroup* mUpsidedownBtnGrp; - - QButtonGroup* mPlacePointBtnGrp; - QButtonGroup* mPlaceLineBtnGrp; - QButtonGroup* mPlacePolygonBtnGrp; - - // background reference font - QFont mRefFont; - bool mDockMode; - int mPreviewSize; - - int mMinPixelLimit; - - bool mLoadSvgParams; - - QgsStringReplacementCollection mSubstitutions; - - void enableDataDefinedAlignment( bool enable ); QgsExpressionContext createExpressionContext() const override; - private slots: - void optionsStackedWidget_CurrentChanged( int indx ); - void showBackgroundRadius( bool show ); - void showBackgroundPenStyle( bool show ); - void on_mShapeSVGPathLineEdit_textChanged( const QString& text ); - void updateLinePlacementOptions(); - void onSubstitutionsChanged( const QgsStringReplacementCollection& substitutions ); - void previewScaleChanged( double scale ); }; -#endif +#endif // QGSLABELINGGUI_H diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 2f42b62ba2d..f2c0dc0c176 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -302,12 +302,14 @@ SET(QGIS_GUI_SRCS qgsshortcutsmanager.cpp qgsslider.cpp qgssublayersdialog.cpp + qgssubstitutionlistwidget.cpp qgssqlcomposerdialog.cpp qgssvgannotationitem.cpp qgstablewidgetbase.cpp qgstabwidget.cpp qgstablewidgetitem.cpp qgstextannotationitem.cpp + qgstextformatwidget.cpp qgstextpreview.cpp qgstrackedvectorlayertools.cpp qgstreewidgetitem.cpp @@ -460,8 +462,10 @@ SET(QGIS_GUI_MOC_HDRS qgsslider.h qgssqlcomposerdialog.h qgssublayersdialog.h + qgssubstitutionlistwidget.h qgstablewidgetbase.h qgstabwidget.h + qgstextformatwidget.h qgstextpreview.h qgstreewidgetitem.h qgsunitselectionwidget.h diff --git a/src/app/qgssubstitutionlistwidget.cpp b/src/gui/qgssubstitutionlistwidget.cpp similarity index 100% rename from src/app/qgssubstitutionlistwidget.cpp rename to src/gui/qgssubstitutionlistwidget.cpp diff --git a/src/app/qgssubstitutionlistwidget.h b/src/gui/qgssubstitutionlistwidget.h similarity index 95% rename from src/app/qgssubstitutionlistwidget.h rename to src/gui/qgssubstitutionlistwidget.h index acd8529a0dc..155fe7c5924 100644 --- a/src/app/qgssubstitutionlistwidget.h +++ b/src/gui/qgssubstitutionlistwidget.h @@ -24,13 +24,13 @@ #include "qgsstringutils.h" /** \class QgsSubstitutionListWidget - * \ingroup app + * \ingroup gui * A widget which allows users to specify a list of substitutions to apply to a string, with * options for exporting and importing substitution lists. * \note added in QGIS 3.0 * \see QgsSubstitutionListDialog */ -class APP_EXPORT QgsSubstitutionListWidget : public QgsPanelWidget, private Ui::QgsSubstitutionListWidgetBase +class GUI_EXPORT QgsSubstitutionListWidget : public QgsPanelWidget, private Ui::QgsSubstitutionListWidgetBase { Q_OBJECT Q_PROPERTY( QgsStringReplacementCollection substitutions READ substitutions WRITE setSubstitutions NOTIFY substitutionsChanged ) @@ -73,12 +73,13 @@ class APP_EXPORT QgsSubstitutionListWidget : public QgsPanelWidget, private Ui:: }; /** \class QgsSubstitutionListDialog - * \ingroup app + * \ingroup gui * A dialog which allows users to specify a list of substitutions to apply to a string, with * options for exporting and importing substitution lists. + * \note added in QGIS 3.0 * \see QgsSubstitutionListWidget */ -class APP_EXPORT QgsSubstitutionListDialog : public QDialog +class GUI_EXPORT QgsSubstitutionListDialog : public QDialog { Q_OBJECT Q_PROPERTY( QgsStringReplacementCollection substitutions READ substitutions WRITE setSubstitutions ) diff --git a/src/gui/qgstextformatwidget.cpp b/src/gui/qgstextformatwidget.cpp new file mode 100644 index 00000000000..934c7e2a9af --- /dev/null +++ b/src/gui/qgstextformatwidget.cpp @@ -0,0 +1,1378 @@ +/*************************************************************************** + qgstextformatwidget.h + --------------------- + begin : June 2009 + copyright : (C) Martin Dobias + email : wonder dot sk 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 "qgstextformatwidget.h" +#include "qgsmapcanvas.h" +#include "qgscharacterselectdialog.h" +#include "qgslogger.h" +#include "qgsfontutils.h" +#include "qgssymbollayerutils.h" +#include "qgssvgcache.h" +#include "qgssvgselectorwidget.h" +#include "qgssubstitutionlistwidget.h" +#include "qgspallabeling.h" // for enum values +#include + +QgsTextFormatWidget::QgsTextFormatWidget( const QgsTextFormat& format, QgsMapCanvas* mapCanvas, QWidget* parent ) + : QWidget( parent ) + , mQuadrantBtnGrp( nullptr ) + , mDirectSymbBtnGrp( nullptr ) + , mUpsidedownBtnGrp( nullptr ) + , mPlacePointBtnGrp( nullptr ) + , mPlaceLineBtnGrp( nullptr ) + , mPlacePolygonBtnGrp( nullptr ) + , mMinPixelLimit( 0 ) + , mWidgetMode( Text ) + , mMapCanvas( mapCanvas ) + , mCharDlg( nullptr ) + , mLoadSvgParams( false ) +{ + initWidget(); + setWidgetMode( Text ); + updateWidgetForFormat( format ); +} + +QgsTextFormatWidget::QgsTextFormatWidget( QgsMapCanvas* mapCanvas, QWidget* parent, Mode mode ) + : QWidget( parent ) + , mQuadrantBtnGrp( nullptr ) + , mDirectSymbBtnGrp( nullptr ) + , mUpsidedownBtnGrp( nullptr ) + , mPlacePointBtnGrp( nullptr ) + , mPlaceLineBtnGrp( nullptr ) + , mPlacePolygonBtnGrp( nullptr ) + , mMinPixelLimit( 0 ) + , mWidgetMode( mode ) + , mMapCanvas( mapCanvas ) + , mCharDlg( nullptr ) + , mLoadSvgParams( false ) +{ + initWidget(); + setWidgetMode( mode ); +} + +void QgsTextFormatWidget::initWidget() +{ + setupUi( this ); + + mPreviewScaleComboBox->setMapCanvas( mMapCanvas ); + mPreviewScaleComboBox->setShowCurrentScaleButton( true ); + connect( mPreviewScaleComboBox, SIGNAL( scaleChanged( double ) ), this, SLOT( previewScaleChanged( double ) ) ); + + Q_FOREACH ( QgsUnitSelectionWidget* unitWidget, findChildren() ) + { + unitWidget->setMapCanvas( mMapCanvas ); + } + mFontSizeUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderMapUnits + << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderPixels ); + mBufferUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + mShapeSizeUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + mShapeOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + mShapeRadiusUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits + << QgsUnitTypes::RenderPixels << QgsUnitTypes::RenderPercentage ); + mShapeBorderWidthUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + mShadowOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + mShadowRadiusUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + mPointOffsetUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + mLineDistanceUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + mRepeatDistanceUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels ); + + mFontLineHeightSpinBox->setClearValue( 1.0 ); + mShapeRotationDblSpnBx->setClearValue( 0.0 ); + mShapeOffsetXSpnBx->setClearValue( 0.0 ); + mShapeOffsetYSpnBx->setClearValue( 0.0 ); + mPointOffsetXSpinBox->setClearValue( 0.0 ); + mPointOffsetYSpinBox->setClearValue( 0.0 ); + mPointAngleSpinBox->setClearValue( 0.0 ); + mFontLetterSpacingSpinBox->setClearValue( 0.0 ); + mFontWordSpacingSpinBox->setClearValue( 0.0 ); + mZIndexSpinBox->setClearValue( 0.0 ); + + mObstacleTypeComboBox->addItem( tr( "Over the feature's interior" ), QgsPalLayerSettings::PolygonInterior ); + mObstacleTypeComboBox->addItem( tr( "Over the feature's boundary" ), QgsPalLayerSettings::PolygonBoundary ); + + mOffsetTypeComboBox->addItem( tr( "From point" ), QgsPalLayerSettings::FromPoint ); + mOffsetTypeComboBox->addItem( tr( "From symbol bounds" ), QgsPalLayerSettings::FromSymbolBounds ); + + mCharDlg = new QgsCharacterSelectorDialog( this ); + + mRefFont = lblFontPreview->font(); + + // internal connections + connect( mFontTranspSlider, SIGNAL( valueChanged( int ) ), mFontTranspSpinBox, SLOT( setValue( int ) ) ); + connect( mFontTranspSpinBox, SIGNAL( valueChanged( int ) ), mFontTranspSlider, SLOT( setValue( int ) ) ); + connect( mBufferTranspSlider, SIGNAL( valueChanged( int ) ), mBufferTranspSpinBox, SLOT( setValue( int ) ) ); + connect( mBufferTranspSpinBox, SIGNAL( valueChanged( int ) ), mBufferTranspSlider, SLOT( setValue( int ) ) ); + connect( mShapeTranspSlider, SIGNAL( valueChanged( int ) ), mShapeTranspSpinBox, SLOT( setValue( int ) ) ); + connect( mShapeTranspSpinBox, SIGNAL( valueChanged( int ) ), mShapeTranspSlider, SLOT( setValue( int ) ) ); + connect( mShadowOffsetAngleDial, SIGNAL( valueChanged( int ) ), mShadowOffsetAngleSpnBx, SLOT( setValue( int ) ) ); + connect( mShadowOffsetAngleSpnBx, SIGNAL( valueChanged( int ) ), mShadowOffsetAngleDial, SLOT( setValue( int ) ) ); + connect( mShadowTranspSlider, SIGNAL( valueChanged( int ) ), mShadowTranspSpnBx, SLOT( setValue( int ) ) ); + connect( mShadowTranspSpnBx, SIGNAL( valueChanged( int ) ), mShadowTranspSlider, SLOT( setValue( int ) ) ); + connect( mLimitLabelChkBox, SIGNAL( toggled( bool ) ), mLimitLabelSpinBox, SLOT( setEnabled( bool ) ) ); + connect( mCheckBoxSubstituteText, SIGNAL( toggled( bool ) ), mToolButtonConfigureSubstitutes, SLOT( setEnabled( bool ) ) ); + + //connections to prevent users removing all line placement positions + connect( chkLineAbove, SIGNAL( toggled( bool ) ), this, SLOT( updateLinePlacementOptions() ) ); + connect( chkLineBelow, SIGNAL( toggled( bool ) ), this, SLOT( updateLinePlacementOptions() ) ); + connect( chkLineOn, SIGNAL( toggled( bool ) ), this, SLOT( updateLinePlacementOptions() ) ); + + populateFontCapitalsComboBox(); + + // color buttons + mPreviewBackgroundBtn->setColorDialogTitle( tr( "Select fill color" ) ); + mPreviewBackgroundBtn->setContext( "labelling" ); + mPreviewBackgroundBtn->setColor( QColor( 255, 255, 255 ) ); + btnTextColor->setColorDialogTitle( tr( "Select text color" ) ); + btnTextColor->setContext( "labelling" ); + btnTextColor->setDefaultColor( Qt::black ); + btnBufferColor->setColorDialogTitle( tr( "Select buffer color" ) ); + btnBufferColor->setContext( "labelling" ); + btnBufferColor->setDefaultColor( Qt::white ); + mShapeBorderColorBtn->setColorDialogTitle( tr( "Select border color" ) ); + mShapeBorderColorBtn->setContext( "labelling" ); + mShapeFillColorBtn->setColorDialogTitle( tr( "Select fill color" ) ); + mShapeFillColorBtn->setContext( "labelling" ); + mShadowColorBtn->setColorDialogTitle( tr( "Select shadow color" ) ); + mShadowColorBtn->setContext( "labelling" ); + mShadowColorBtn->setDefaultColor( Qt::black ); + + // set up quadrant offset button group + mQuadrantBtnGrp = new QButtonGroup( this ); + mQuadrantBtnGrp->addButton( mPointOffsetAboveLeft, ( int )QgsPalLayerSettings::QuadrantAboveLeft ); + mQuadrantBtnGrp->addButton( mPointOffsetAbove, ( int )QgsPalLayerSettings::QuadrantAbove ); + mQuadrantBtnGrp->addButton( mPointOffsetAboveRight, ( int )QgsPalLayerSettings::QuadrantAboveRight ); + mQuadrantBtnGrp->addButton( mPointOffsetLeft, ( int )QgsPalLayerSettings::QuadrantLeft ); + mQuadrantBtnGrp->addButton( mPointOffsetOver, ( int )QgsPalLayerSettings::QuadrantOver ); + mQuadrantBtnGrp->addButton( mPointOffsetRight, ( int )QgsPalLayerSettings::QuadrantRight ); + mQuadrantBtnGrp->addButton( mPointOffsetBelowLeft, ( int )QgsPalLayerSettings::QuadrantBelowLeft ); + mQuadrantBtnGrp->addButton( mPointOffsetBelow, ( int )QgsPalLayerSettings::QuadrantBelow ); + mQuadrantBtnGrp->addButton( mPointOffsetBelowRight, ( int )QgsPalLayerSettings::QuadrantBelowRight ); + mQuadrantBtnGrp->setExclusive( true ); + + // setup direction symbol(s) button group + mDirectSymbBtnGrp = new QButtonGroup( this ); + mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnLR, ( int )QgsPalLayerSettings::SymbolLeftRight ); + mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnAbove, ( int )QgsPalLayerSettings::SymbolAbove ); + mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnBelow, ( int )QgsPalLayerSettings::SymbolBelow ); + mDirectSymbBtnGrp->setExclusive( true ); + + // upside-down labels button group + mUpsidedownBtnGrp = new QButtonGroup( this ); + mUpsidedownBtnGrp->addButton( mUpsidedownRadioOff, ( int )QgsPalLayerSettings::Upright ); + mUpsidedownBtnGrp->addButton( mUpsidedownRadioDefined, ( int )QgsPalLayerSettings::ShowDefined ); + mUpsidedownBtnGrp->addButton( mUpsidedownRadioAll, ( int )QgsPalLayerSettings::ShowAll ); + mUpsidedownBtnGrp->setExclusive( true ); + + //mShapeCollisionsChkBx->setVisible( false ); // until implemented + + // post updatePlacementWidgets() connections + connect( chkLineAbove, SIGNAL( toggled( bool ) ), this, SLOT( updatePlacementWidgets() ) ); + connect( chkLineBelow, SIGNAL( toggled( bool ) ), this, SLOT( updatePlacementWidgets() ) ); + + // setup point placement button group + mPlacePointBtnGrp = new QButtonGroup( this ); + mPlacePointBtnGrp->addButton( radPredefinedOrder, ( int )QgsPalLayerSettings::OrderedPositionsAroundPoint ); + mPlacePointBtnGrp->addButton( radAroundPoint, ( int )QgsPalLayerSettings::AroundPoint ); + mPlacePointBtnGrp->addButton( radOverPoint, ( int )QgsPalLayerSettings::OverPoint ); + mPlacePointBtnGrp->setExclusive( true ); + connect( mPlacePointBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePlacementWidgets() ) ); + + // setup line placement button group (assigned enum id currently unused) + mPlaceLineBtnGrp = new QButtonGroup( this ); + mPlaceLineBtnGrp->addButton( radLineParallel, ( int )QgsPalLayerSettings::Line ); + mPlaceLineBtnGrp->addButton( radLineCurved, ( int )QgsPalLayerSettings::Curved ); + mPlaceLineBtnGrp->addButton( radLineHorizontal, ( int )QgsPalLayerSettings::Horizontal ); + mPlaceLineBtnGrp->setExclusive( true ); + connect( mPlaceLineBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePlacementWidgets() ) ); + + // setup polygon placement button group (assigned enum id currently unused) + mPlacePolygonBtnGrp = new QButtonGroup( this ); + mPlacePolygonBtnGrp->addButton( radOverCentroid, ( int )QgsPalLayerSettings::OverPoint ); + mPlacePolygonBtnGrp->addButton( radAroundCentroid, ( int )QgsPalLayerSettings::AroundPoint ); + mPlacePolygonBtnGrp->addButton( radPolygonHorizontal, ( int )QgsPalLayerSettings::Horizontal ); + mPlacePolygonBtnGrp->addButton( radPolygonFree, ( int )QgsPalLayerSettings::Free ); + mPlacePolygonBtnGrp->addButton( radPolygonPerimeter, ( int )QgsPalLayerSettings::Line ); + mPlacePolygonBtnGrp->addButton( radPolygonPerimeterCurved, ( int )QgsPalLayerSettings::PerimeterCurved ); + mPlacePolygonBtnGrp->setExclusive( true ); + connect( mPlacePolygonBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePlacementWidgets() ) ); + + // TODO: is this necessary? maybe just use the data defined-only rotation? + mPointAngleDDBtn->setVisible( false ); + + // Global settings group for groupboxes' saved/retored collapsed state + // maintains state across different dialogs + Q_FOREACH ( QgsCollapsibleGroupBox *grpbox, findChildren() ) + { + grpbox->setSettingGroup( QString( "mAdvLabelingDlg" ) ); + } + + connect( groupBox_mPreview, + SIGNAL( collapsedStateChanged( bool ) ), + this, + SLOT( collapseSample( bool ) ) ); + + // get rid of annoying outer focus rect on Mac + mLabelingOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect, false ); + + QSettings settings; + + // reset horiz strech of left side of options splitter (set to 1 for previewing in Qt Designer) + QSizePolicy policy( mLabelingOptionsListFrame->sizePolicy() ); + policy.setHorizontalStretch( 0 ); + mLabelingOptionsListFrame->setSizePolicy( policy ); + if ( !settings.contains( QString( "/Windows/Labeling/OptionsSplitState" ) ) ) + { + // set left list widget width on intial showing + QList splitsizes; + splitsizes << 115; + mLabelingOptionsSplitter->setSizes( splitsizes ); + } + + // set up reverse connection from stack to list + connect( mLabelStackedWidget, SIGNAL( currentChanged( int ) ), this, SLOT( optionsStackedWidget_CurrentChanged( int ) ) ); + + // restore dialog, splitters and current tab + mFontPreviewSplitter->restoreState( settings.value( QString( "/Windows/Labeling/FontPreviewSplitState" ) ).toByteArray() ); + mLabelingOptionsSplitter->restoreState( settings.value( QString( "/Windows/Labeling/OptionsSplitState" ) ).toByteArray() ); + + mLabelingOptionsListWidget->setCurrentRow( settings.value( QString( "/Windows/Labeling/Tab" ), 0 ).toInt() ); + + setDockMode( false ); + + + QList widgets; + widgets << btnBufferColor + << btnTextColor + << chkLabelPerFeaturePart + << chkLineAbove + << chkLineBelow + << chkLineOn + << chkLineOrientationDependent + << chkMergeLines + << chkPreserveRotation + << comboBlendMode + << comboBufferBlendMode + << mAlwaysShowDDBtn + << mBufferBlendModeDDBtn + << mBufferColorDDBtn + << mBufferDrawChkBx + << mBufferDrawDDBtn + << mBufferJoinStyleComboBox + << mBufferJoinStyleDDBtn + << mBufferSizeDDBtn + << mBufferTranspDDBtn + << mBufferTranspFillChbx + << mBufferTranspSpinBox + << mBufferUnitsDDBtn + << mCentroidDDBtn + << mCentroidInsideCheckBox + << mChkNoObstacle + << mCoordAlignmentHDDBtn + << mCoordAlignmentVDDBtn + << mCoordRotationDDBtn + << mCoordXDDBtn + << mCoordYDDBtn + << mDirectSymbChkBx + << mDirectSymbDDBtn + << mDirectSymbLeftDDBtn + << mDirectSymbLeftLineEdit + << mDirectSymbPlacementDDBtn + << mDirectSymbRevChkBx + << mDirectSymbRevDDBtn + << mDirectSymbRightDDBtn + << mDirectSymbRightLineEdit + << mFitInsidePolygonCheckBox + << mFontBlendModeDDBtn + << mFontBoldDDBtn + << mFontCapitalsComboBox + << mFontCaseDDBtn + << mFontColorDDBtn + << mFontDDBtn + << mFontItalicDDBtn + << mFontLetterSpacingDDBtn + << mFontLetterSpacingSpinBox + << mFontLimitPixelChkBox + << mFontLimitPixelDDBtn + << mFontLineHeightDDBtn + << mFontLineHeightSpinBox + << mFontMaxPixelDDBtn + << mFontMaxPixelSpinBox + << mFontMinPixelDDBtn + << mFontMinPixelSpinBox + << mFontMultiLineAlignComboBox + << mFontMultiLineAlignDDBtn + << mFontSizeDDBtn + << mFontSizeSpinBox + << mFontStrikeoutDDBtn + << mFontStyleComboBox + << mFontStyleDDBtn + << mFontTranspDDBtn + << mFontTranspSpinBox + << mFontUnderlineDDBtn + << mFontUnitsDDBtn + << mFontWordSpacingDDBtn + << mFontWordSpacingSpinBox + << mFormatNumChkBx + << mFormatNumDDBtn + << mFormatNumDecimalsDDBtn + << mFormatNumDecimalsSpnBx + << mFormatNumPlusSignChkBx + << mFormatNumPlusSignDDBtn + << mIsObstacleDDBtn + << mLimitLabelChkBox + << mLimitLabelSpinBox + << mLineDistanceDDBtn + << mLineDistanceSpnBx + << mLineDistanceUnitDDBtn + << mLineDistanceUnitWidget + << mMaxCharAngleDDBtn + << mMaxCharAngleInDSpinBox + << mMaxCharAngleOutDSpinBox + << mMinSizeSpinBox + << mObstacleFactorDDBtn + << mObstacleFactorSlider + << mObstacleTypeComboBox + << mOffsetTypeComboBox + << mPalShowAllLabelsForLayerChkBx + << mPointAngleDDBtn + << mPointAngleSpinBox + << mPointOffsetDDBtn + << mPointOffsetUnitsDDBtn + << mPointOffsetUnitWidget + << mPointOffsetXSpinBox + << mPointOffsetYSpinBox + << mPointPositionOrderDDBtn + << mPointQuadOffsetDDBtn + << mPreviewBackgroundBtn + << mPreviewTextEdit + << mPriorityDDBtn + << mPrioritySlider + << mRepeatDistanceDDBtn + << mRepeatDistanceSpinBox + << mRepeatDistanceUnitDDBtn + << mRepeatDistanceUnitWidget + << mScaleBasedVisibilityChkBx + << mScaleBasedVisibilityDDBtn + << mScaleBasedVisibilityMaxDDBtn + << mScaleBasedVisibilityMaxSpnBx + << mScaleBasedVisibilityMinDDBtn + << mScaleBasedVisibilityMinSpnBx + << mShadowBlendCmbBx + << mShadowBlendDDBtn + << mShadowColorBtn + << mShadowColorDDBtn + << mShadowDrawChkBx + << mShadowDrawDDBtn + << mShadowOffsetAngleDDBtn + << mShadowOffsetAngleSpnBx + << mShadowOffsetDDBtn + << mShadowOffsetGlobalChkBx + << mShadowOffsetSpnBx + << mShadowOffsetUnitsDDBtn + << mShadowOffsetUnitWidget + << mShadowRadiusAlphaChkBx + << mShadowRadiusDDBtn + << mShadowRadiusDblSpnBx + << mShadowRadiusUnitsDDBtn + << mShadowRadiusUnitWidget + << mShadowScaleDDBtn + << mShadowScaleSpnBx + << mShadowTranspDDBtn + << mShadowTranspSpnBx + << mShadowUnderCmbBx + << mShadowUnderDDBtn + << mShapeBlendCmbBx + << mShapeBlendModeDDBtn + << mShapeBorderColorBtn + << mShapeBorderColorDDBtn + << mShapeBorderUnitsDDBtn + << mShapeBorderWidthDDBtn + << mShapeBorderWidthSpnBx + << mShapeBorderWidthUnitWidget + << mShapeDrawChkBx + << mShapeDrawDDBtn + << mShapeFillColorBtn + << mShapeFillColorDDBtn + << mShapeOffsetDDBtn + << mShapeOffsetUnitsDDBtn + << mShapeOffsetXSpnBx + << mShapeOffsetYSpnBx + << mShapeOffsetUnitWidget + << mShapePenStyleCmbBx + << mShapePenStyleDDBtn + << mShapeRadiusDDBtn + << mShapeRadiusUnitsDDBtn + << mShapeRadiusXDbSpnBx + << mShapeRadiusYDbSpnBx + << mShapeRotationCmbBx + << mShapeRotationDDBtn + << mShapeRotationDblSpnBx + << mShapeRotationTypeDDBtn + << mShapeRadiusUnitWidget + << mShapeSVGPathDDBtn + << mShapeSVGPathLineEdit + << mShapeSizeCmbBx + << mShapeSizeTypeDDBtn + << mShapeSizeUnitsDDBtn + << mShapeSizeUnitWidget + << mShapeSizeXDDBtn + << mShapeSizeXSpnBx + << mShapeSizeYDDBtn + << mShapeSizeYSpnBx + << mShapeTranspDDBtn + << mShapeTranspSpinBox + << mShapeTypeCmbBx + << mShapeTypeDDBtn + << mShowLabelDDBtn + << mWrapCharDDBtn + << mZIndexDDBtn + << mZIndexSpinBox + << spinBufferSize + << wrapCharacterEdit + << mCentroidRadioVisible + << mCentroidRadioWhole + << mDirectSymbRadioBtnAbove + << mDirectSymbRadioBtnBelow + << mDirectSymbRadioBtnLR + << mUpsidedownRadioAll + << mUpsidedownRadioDefined + << mUpsidedownRadioOff + << radAroundCentroid + << radAroundPoint + << radLineCurved + << radLineHorizontal + << radLineParallel + << radOverCentroid + << radOverPoint + << radPolygonFree + << radPolygonHorizontal + << radPolygonPerimeter + << radPolygonPerimeterCurved + << radPredefinedOrder + << mFieldExpressionWidget + << mCheckBoxSubstituteText; + connectValueChanged( widgets, SLOT( updatePreview() ) ); + + connect( mQuadrantBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePreview() ) ); + + // set correct initial tab to match displayed setting page + whileBlocking( mOptionsTab )->setCurrentIndex( mLabelStackedWidget->currentIndex() ); + + if ( mMapCanvas ) + { + lblFontPreview->setMapUnits( mMapCanvas->mapSettings().mapUnits() ); + mPreviewScaleComboBox->setScale( 1.0 / mMapCanvas->mapSettings().scale() ); + } +} + +void QgsTextFormatWidget::setWidgetMode( QgsTextFormatWidget::Mode mode ) +{ + mWidgetMode = mode; + switch ( mode ) + { + case Labeling: + toggleDDButtons( true ); + break; + + case Text: + toggleDDButtons( false ); + delete mLabelingOptionsListWidget->takeItem( 6 ); + delete mLabelingOptionsListWidget->takeItem( 5 ); + mOptionsTab->removeTab( 6 ); + mOptionsTab->removeTab( 5 ); + + frameLabelWith->hide(); + mDirectSymbolsFrame->hide(); + mFormatNumFrame->hide(); + mFormatNumChkBx->hide(); + mFormatNumDDBtn->hide(); + mSubstitutionsFrame->hide(); + mFontBoldBtn->hide(); + mFontItalicBtn->hide(); + + break; + } +} + +void QgsTextFormatWidget::toggleDDButtons( bool visible ) +{ + Q_FOREACH ( QgsDataDefinedButton* button, findChildren< QgsDataDefinedButton* >() ) + { + button->setVisible( visible ); + } +} + +void QgsTextFormatWidget::setDockMode( bool enabled ) +{ + mOptionsTab->setVisible( enabled ); + mOptionsTab->setTabToolTip( 0, tr( "Text" ) ); + mOptionsTab->setTabToolTip( 1, tr( "Formatting" ) ); + mOptionsTab->setTabToolTip( 2, tr( "Buffer" ) ); + mOptionsTab->setTabToolTip( 3, tr( "Background" ) ); + mOptionsTab->setTabToolTip( 4, tr( "Shadow" ) ); + mOptionsTab->setTabToolTip( 5, tr( "Placement" ) ); + mOptionsTab->setTabToolTip( 6, tr( "Rendering" ) ); + + mLabelingOptionsListFrame->setVisible( !enabled ); + groupBox_mPreview->setVisible( !enabled ); + mDockMode = enabled; +} + +void QgsTextFormatWidget::connectValueChanged( const QList& widgets, const char *slot ) +{ + Q_FOREACH ( QWidget* widget, widgets ) + { + if ( QgsDataDefinedButton* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( dataDefinedActivated( bool ) ), this, slot ); + connect( w, SIGNAL( dataDefinedChanged( QString ) ), this, slot ); + } + else if ( QgsFieldExpressionWidget* w = qobject_cast< QgsFieldExpressionWidget*>( widget ) ) + { + connect( w, SIGNAL( fieldChanged( QString ) ), this, slot ); + } + else if ( QgsUnitSelectionWidget* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( changed() ), this, slot ); + } + else if ( QComboBox* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( currentIndexChanged( int ) ), this, slot ); + } + else if ( QSpinBox* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( valueChanged( int ) ), this, slot ); + } + else if ( QDoubleSpinBox* w = qobject_cast( widget ) ) + { + connect( w , SIGNAL( valueChanged( double ) ), this, slot ); + } + else if ( QgsColorButton* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( colorChanged( QColor ) ), this, slot ); + } + else if ( QCheckBox* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( toggled( bool ) ), this, slot ); + } + else if ( QRadioButton* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( toggled( bool ) ), this, slot ); + } + else if ( QLineEdit* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( textEdited( QString ) ), this, slot ); + } + else if ( QSlider* w = qobject_cast( widget ) ) + { + connect( w, SIGNAL( valueChanged( int ) ), this, slot ); + } + else + { + QgsLogger::warning( QString( "Could not create connection for widget %1" ).arg( widget->objectName() ) ); + } + } +} + +void QgsTextFormatWidget::updateWidgetForFormat( const QgsTextFormat& format ) +{ + QgsTextBufferSettings buffer = format.buffer(); + QgsTextBackgroundSettings background = format.background(); + QgsTextShadowSettings shadow = format.shadow(); + + // buffer + mBufferDrawChkBx->setChecked( buffer.enabled() ); + spinBufferSize->setValue( buffer.size() ); + mBufferUnitWidget->setUnit( buffer.sizeUnit() ); + mBufferUnitWidget->setMapUnitScale( buffer.sizeMapUnitScale() ); + btnBufferColor->setColor( buffer.color() ); + mBufferTranspSpinBox->setValue( 100 - 100 * buffer.opacity() ); + mBufferJoinStyleComboBox->setPenJoinStyle( buffer.joinStyle() ); + mBufferTranspFillChbx->setChecked( buffer.fillBufferInterior() ); + comboBufferBlendMode->setBlendMode( buffer.blendMode() ); + + + mFontSizeUnitWidget->setUnit( format.sizeUnit() ); + mFontSizeUnitWidget->setMapUnitScale( format.sizeMapUnitScale() ); + mRefFont = format.font(); + mFontSizeSpinBox->setValue( format.size() ); + btnTextColor->setColor( format.color() ); + mFontTranspSpinBox->setValue( 100 - 100 * format.opacity() ); + comboBlendMode->setBlendMode( format.blendMode() ); + + mFontWordSpacingSpinBox->setValue( format.font().wordSpacing() ); + mFontLetterSpacingSpinBox->setValue( format.font().letterSpacing() ); + + QgsFontUtils::updateFontViaStyle( mRefFont, format.namedStyle() ); + updateFont( mRefFont ); + + // show 'font not found' if substitution has occurred (should come after updateFont()) + mFontMissingLabel->setVisible( !format.fontFound() ); + if ( !format.fontFound() ) + { + QString missingTxt = tr( "%1 not found. Default substituted." ); + QString txtPrepend = tr( "Chosen font" ); + if ( !format.resolvedFontFamily().isEmpty() ) + { + txtPrepend = QString( "'%1'" ).arg( format.resolvedFontFamily() ); + } + mFontMissingLabel->setText( missingTxt.arg( txtPrepend ) ); + + // ensure user is sent to 'Text style' section to see notice + mLabelingOptionsListWidget->setCurrentRow( 0 ); + } + mFontLineHeightSpinBox->setValue( format.lineHeight() ); + + // shape background + mShapeDrawChkBx->setChecked( background.enabled() ); + mShapeTypeCmbBx->blockSignals( true ); + mShapeTypeCmbBx->setCurrentIndex( background.type() ); + mShapeTypeCmbBx->blockSignals( false ); + mShapeSVGPathLineEdit->setText( background.svgFile() ); + + mShapeSizeCmbBx->setCurrentIndex( background.sizeType() ); + mShapeSizeXSpnBx->setValue( background.size().width() ); + mShapeSizeYSpnBx->setValue( background.size().height() ); + mShapeSizeUnitWidget->setUnit( background.sizeUnit() ); + mShapeSizeUnitWidget->setMapUnitScale( background.sizeMapUnitScale() ); + mShapeRotationCmbBx->setCurrentIndex( background.rotationType() ); + mShapeRotationDblSpnBx->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync ); + mShapeRotationDDBtn->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync ); + mShapeRotationDblSpnBx->setValue( background.rotation() ); + mShapeOffsetXSpnBx->setValue( background.offset().x() ); + mShapeOffsetYSpnBx->setValue( background.offset().y() ); + mShapeOffsetUnitWidget->setUnit( background.offsetUnit() ); + mShapeOffsetUnitWidget->setMapUnitScale( background.offsetMapUnitScale() ); + mShapeRadiusXDbSpnBx->setValue( background.radii().width() ); + mShapeRadiusYDbSpnBx->setValue( background.radii().height() ); + mShapeRadiusUnitWidget->setUnit( background.radiiUnit() ); + mShapeRadiusUnitWidget->setMapUnitScale( background.radiiMapUnitScale() ); + + mShapeFillColorBtn->setColor( background.fillColor() ); + mShapeBorderColorBtn->setColor( background.borderColor() ); + mShapeBorderWidthSpnBx->setValue( background.borderWidth() ); + mShapeBorderWidthUnitWidget->setUnit( background.borderWidthUnit() ); + mShapeBorderWidthUnitWidget->setMapUnitScale( background.borderWidthMapUnitScale() ); + mShapePenStyleCmbBx->setPenJoinStyle( background.joinStyle() ); + + mShapeTranspSpinBox->setValue( 100 - background.opacity() * 100.0 ); + mShapeBlendCmbBx->setBlendMode( background.blendMode() ); + + mLoadSvgParams = false; + on_mShapeTypeCmbBx_currentIndexChanged( background.type() ); // force update of shape background gui + + // drop shadow + mShadowDrawChkBx->setChecked( shadow.enabled() ); + mShadowUnderCmbBx->setCurrentIndex( shadow.shadowPlacement() ); + mShadowOffsetAngleSpnBx->setValue( shadow.offsetAngle() ); + mShadowOffsetSpnBx->setValue( shadow.offsetDistance() ); + mShadowOffsetUnitWidget->setUnit( shadow.offsetUnit() ); + mShadowOffsetUnitWidget->setMapUnitScale( shadow.offsetMapUnitScale() ); + mShadowOffsetGlobalChkBx->setChecked( shadow.offsetGlobal() ); + + mShadowRadiusDblSpnBx->setValue( shadow.blurRadius() ); + mShadowRadiusUnitWidget->setUnit( shadow.blurRadiusUnit() ); + mShadowRadiusUnitWidget->setMapUnitScale( shadow.blurRadiusMapUnitScale() ); + mShadowRadiusAlphaChkBx->setChecked( shadow.blurAlphaOnly() ); + mShadowTranspSpnBx->setValue( 100 - shadow.opacity() * 100.0 ); + mShadowScaleSpnBx->setValue( shadow.scale() ); + + mShadowColorBtn->setColor( shadow.color() ); + mShadowBlendCmbBx->setBlendMode( shadow.blendMode() ); + +} + +QgsTextFormatWidget::~QgsTextFormatWidget() +{ + QSettings settings; + settings.setValue( QString( "/Windows/Labeling/FontPreviewSplitState" ), mFontPreviewSplitter->saveState() ); + settings.setValue( QString( "/Windows/Labeling/OptionsSplitState" ), mLabelingOptionsSplitter->saveState() ); + settings.setValue( QString( "/Windows/Labeling/Tab" ), mLabelingOptionsListWidget->currentRow() ); +} + +QgsTextFormat QgsTextFormatWidget::format() const +{ + QgsTextFormat format; + format.setColor( btnTextColor->color() ); + format.setFont( mRefFont ); + format.setSize( mFontSizeSpinBox->value() ); + format.setNamedStyle( mFontStyleComboBox->currentText() ); + format.setOpacity( 1.0 - mFontTranspSpinBox->value() / 100.0 ); + format.setBlendMode( comboBlendMode->blendMode() ); + format.setSizeUnit( mFontSizeUnitWidget->unit() ); + format.setSizeMapUnitScale( mFontSizeUnitWidget->getMapUnitScale() ); + format.setLineHeight( mFontLineHeightSpinBox->value() ); + + // buffer + QgsTextBufferSettings buffer; + buffer.setEnabled( mBufferDrawChkBx->isChecked() ); + buffer.setSize( spinBufferSize->value() ); + buffer.setColor( btnBufferColor->color() ); + buffer.setOpacity( 1.0 - mBufferTranspSpinBox->value() / 100.0 ); + buffer.setSizeUnit( mBufferUnitWidget->unit() ); + buffer.setSizeMapUnitScale( mBufferUnitWidget->getMapUnitScale() ); + buffer.setJoinStyle( mBufferJoinStyleComboBox->penJoinStyle() ); + buffer.setFillBufferInterior( mBufferTranspFillChbx->isChecked() ); + buffer.setBlendMode( comboBufferBlendMode->blendMode() ); + format.setBuffer( buffer ); + + // shape background + QgsTextBackgroundSettings background; + background.setEnabled( mShapeDrawChkBx->isChecked() ); + background.setType(( QgsTextBackgroundSettings::ShapeType )mShapeTypeCmbBx->currentIndex() ); + background.setSvgFile( mShapeSVGPathLineEdit->text() ); + background.setSizeType(( QgsTextBackgroundSettings::SizeType )mShapeSizeCmbBx->currentIndex() ); + background.setSize( QSizeF( mShapeSizeXSpnBx->value(), mShapeSizeYSpnBx->value() ) ); + background.setSizeUnit( mShapeSizeUnitWidget->unit() ); + background.setSizeMapUnitScale( mShapeSizeUnitWidget->getMapUnitScale() ); + background.setRotationType(( QgsTextBackgroundSettings::RotationType )( mShapeRotationCmbBx->currentIndex() ) ); + background.setRotation( mShapeRotationDblSpnBx->value() ); + background.setOffset( QPointF( mShapeOffsetXSpnBx->value(), mShapeOffsetYSpnBx->value() ) ); + background.setOffsetUnit( mShapeOffsetUnitWidget->unit() ); + background.setOffsetMapUnitScale( mShapeOffsetUnitWidget->getMapUnitScale() ); + background.setRadii( QSizeF( mShapeRadiusXDbSpnBx->value(), mShapeRadiusYDbSpnBx->value() ) ); + background.setRadiiUnit( mShapeRadiusUnitWidget->unit() ); + background.setRadiiMapUnitScale( mShapeRadiusUnitWidget->getMapUnitScale() ); + + background.setFillColor( mShapeFillColorBtn->color() ); + background.setBorderColor( mShapeBorderColorBtn->color() ); + background.setBorderWidth( mShapeBorderWidthSpnBx->value() ); + background.setBorderWidthUnit( mShapeBorderWidthUnitWidget->unit() ); + background.setBorderWidthMapUnitScale( mShapeBorderWidthUnitWidget->getMapUnitScale() ); + background.setJoinStyle( mShapePenStyleCmbBx->penJoinStyle() ); + background.setOpacity( 1.0 - mShapeTranspSpinBox->value() / 100.0 ); + background.setBlendMode( mShapeBlendCmbBx->blendMode() ); + format.setBackground( background ); + + // drop shadow + QgsTextShadowSettings shadow; + shadow.setEnabled( mShadowDrawChkBx->isChecked() ); + shadow.setShadowPlacement(( QgsTextShadowSettings::ShadowPlacement )mShadowUnderCmbBx->currentIndex() ); + shadow.setOffsetAngle( mShadowOffsetAngleSpnBx->value() ); + shadow.setOffsetDistance( mShadowOffsetSpnBx->value() ); + shadow.setOffsetUnit( mShadowOffsetUnitWidget->unit() ); + shadow.setOffsetMapUnitScale( mShadowOffsetUnitWidget->getMapUnitScale() ); + shadow.setOffsetGlobal( mShadowOffsetGlobalChkBx->isChecked() ); + shadow.setBlurRadius( mShadowRadiusDblSpnBx->value() ); + shadow.setBlurRadiusUnit( mShadowRadiusUnitWidget->unit() ); + shadow.setBlurRadiusMapUnitScale( mShadowRadiusUnitWidget->getMapUnitScale() ); + shadow.setBlurAlphaOnly( mShadowRadiusAlphaChkBx->isChecked() ); + shadow.setOpacity( 1.0 - mShadowTranspSpnBx->value() / 100.0 ); + shadow.setScale( mShadowScaleSpnBx->value() ); + shadow.setColor( mShadowColorBtn->color() ); + shadow.setBlendMode( mShadowBlendCmbBx->blendMode() ); + format.setShadow( shadow ); + + return format; +} + +void QgsTextFormatWidget::optionsStackedWidget_CurrentChanged( int indx ) +{ + mLabelingOptionsListWidget->blockSignals( true ); + mLabelingOptionsListWidget->setCurrentRow( indx ); + mLabelingOptionsListWidget->blockSignals( false ); +} + +void QgsTextFormatWidget::collapseSample( bool collapse ) +{ + if ( collapse ) + { + QList splitSizes = mFontPreviewSplitter->sizes(); + if ( splitSizes[0] > groupBox_mPreview->height() ) + { + int delta = splitSizes[0] - groupBox_mPreview->height(); + splitSizes[0] -= delta; + splitSizes[1] += delta; + mFontPreviewSplitter->setSizes( splitSizes ); + } + } +} + +void QgsTextFormatWidget::changeTextColor( const QColor &color ) +{ + Q_UNUSED( color ) + updatePreview(); +} + +void QgsTextFormatWidget::updateFont( const QFont& font ) +{ + // update background reference font + if ( font != mRefFont ) + { + mRefFont = font; + } + + // test if font is actually available + // NOTE: QgsFontUtils::fontMatchOnSystem may fail here, just crosscheck family + mFontMissingLabel->setVisible( !QgsFontUtils::fontFamilyMatchOnSystem( mRefFont.family() ) ); + + mDirectSymbLeftLineEdit->setFont( mRefFont ); + mDirectSymbRightLineEdit->setFont( mRefFont ); + + blockFontChangeSignals( true ); + mFontFamilyCmbBx->setCurrentFont( mRefFont ); + populateFontStyleComboBox(); + int idx = mFontCapitalsComboBox->findData( QVariant(( unsigned int ) mRefFont.capitalization() ) ); + mFontCapitalsComboBox->setCurrentIndex( idx == -1 ? 0 : idx ); + mFontUnderlineBtn->setChecked( mRefFont.underline() ); + mFontStrikethroughBtn->setChecked( mRefFont.strikeOut() ); + blockFontChangeSignals( false ); + + // update font name with font face +// font.setPixelSize( 24 ); + + updatePreview(); +} + +void QgsTextFormatWidget::blockFontChangeSignals( bool blk ) +{ + mFontFamilyCmbBx->blockSignals( blk ); + mFontStyleComboBox->blockSignals( blk ); + mFontCapitalsComboBox->blockSignals( blk ); + mFontUnderlineBtn->blockSignals( blk ); + mFontStrikethroughBtn->blockSignals( blk ); + mFontWordSpacingSpinBox->blockSignals( blk ); + mFontLetterSpacingSpinBox->blockSignals( blk ); +} + +void QgsTextFormatWidget::updatePreview() +{ + // In dock mode we don't have a preview we + // just let stuff know we have changed because + // there might be live updates connected. + if ( mDockMode ) + { + emit widgetChanged(); + return; + } + + scrollPreview(); + lblFontPreview->setFormat( format() ); +} + +void QgsTextFormatWidget::scrollPreview() +{ + scrollArea_mPreview->ensureVisible( 0, 0, 0, 0 ); +} + +void QgsTextFormatWidget::setPreviewBackground( const QColor& color ) +{ + scrollArea_mPreview->widget()->setStyleSheet( QString( "background: rgb(%1, %2, %3);" ).arg( QString::number( color.red() ), + QString::number( color.green() ), + QString::number( color.blue() ) ) ); +} + +void QgsTextFormatWidget::changeBufferColor( const QColor &color ) +{ + Q_UNUSED( color ) + updatePreview(); +} + +void QgsTextFormatWidget::updatePlacementWidgets() +{ + QWidget* curWdgt = stackedPlacement->currentWidget(); + + bool showLineFrame = false; + bool showCentroidFrame = false; + bool showQuadrantFrame = false; + bool showFixedQuadrantFrame = false; + bool showPlacementPriorityFrame = false; + bool showOffsetTypeFrame = false; + bool showOffsetFrame = false; + bool showDistanceFrame = false; + bool showRotationFrame = false; + bool showMaxCharAngleFrame = false; + + bool enableMultiLinesFrame = true; + + if (( curWdgt == pagePoint && radAroundPoint->isChecked() ) + || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) ) + { + showCentroidFrame = ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ); + showDistanceFrame = true; + //showRotationFrame = true; // TODO: uncomment when supported + if ( curWdgt == pagePoint ) + { + showQuadrantFrame = true; + } + } + else if (( curWdgt == pagePoint && radOverPoint->isChecked() ) + || ( curWdgt == pagePolygon && radOverCentroid->isChecked() ) ) + { + showCentroidFrame = ( curWdgt == pagePolygon && radOverCentroid->isChecked() ); + showQuadrantFrame = true; + showFixedQuadrantFrame = true; + showOffsetFrame = true; + showRotationFrame = true; + } + else if ( curWdgt == pagePoint && radPredefinedOrder->isChecked() ) + { + showDistanceFrame = true; + showPlacementPriorityFrame = true; + showOffsetTypeFrame = true; + } + else if (( curWdgt == pageLine && radLineParallel->isChecked() ) + || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) + || ( curWdgt == pageLine && radLineCurved->isChecked() ) + || ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() ) ) + { + showLineFrame = true; + showDistanceFrame = true; + //showRotationFrame = true; // TODO: uncomment when supported + + bool offline = chkLineAbove->isChecked() || chkLineBelow->isChecked(); + chkLineOrientationDependent->setEnabled( offline ); + mPlacementDistanceFrame->setEnabled( offline ); + + bool isCurved = ( curWdgt == pageLine && radLineCurved->isChecked() ) + || ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() ); + showMaxCharAngleFrame = isCurved; + // TODO: enable mMultiLinesFrame when supported for curved labels + enableMultiLinesFrame = !isCurved; + } + + mPlacementLineFrame->setVisible( showLineFrame ); + mPlacementCentroidFrame->setVisible( showCentroidFrame ); + mPlacementQuadrantFrame->setVisible( showQuadrantFrame ); + mPlacementFixedQuadrantFrame->setVisible( showFixedQuadrantFrame ); + mPlacementCartographicFrame->setVisible( showPlacementPriorityFrame ); + mPlacementOffsetFrame->setVisible( showOffsetFrame ); + mPlacementDistanceFrame->setVisible( showDistanceFrame ); + mPlacementOffsetTypeFrame->setVisible( showOffsetTypeFrame ); + mPlacementRotationFrame->setVisible( showRotationFrame ); + mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon && + ( radPolygonPerimeter->isChecked() || radPolygonPerimeterCurved->isChecked() ) ) ); + mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame ); + + mMultiLinesFrame->setEnabled( enableMultiLinesFrame ); +} + +void QgsTextFormatWidget::populateFontCapitalsComboBox() +{ + mFontCapitalsComboBox->addItem( tr( "No change" ), QVariant( 0 ) ); + mFontCapitalsComboBox->addItem( tr( "All uppercase" ), QVariant( 1 ) ); + mFontCapitalsComboBox->addItem( tr( "All lowercase" ), QVariant( 2 ) ); + // Small caps doesn't work right with QPainterPath::addText() + // https://bugreports.qt-project.org/browse/QTBUG-13965 +// mFontCapitalsComboBox->addItem( tr( "Small caps" ), QVariant( 3 ) ); + mFontCapitalsComboBox->addItem( tr( "Capitalize first letter" ), QVariant( 4 ) ); +} + +void QgsTextFormatWidget::populateFontStyleComboBox() +{ + mFontStyleComboBox->clear(); + Q_FOREACH ( const QString &style, mFontDB.styles( mRefFont.family() ) ) + { + mFontStyleComboBox->addItem( style ); + } + + int curIndx = 0; + int stylIndx = mFontStyleComboBox->findText( mFontDB.styleString( mRefFont ) ); + if ( stylIndx > -1 ) + { + curIndx = stylIndx; + } + + mFontStyleComboBox->setCurrentIndex( curIndx ); +} + +void QgsTextFormatWidget::on_mFontSizeSpinBox_valueChanged( double d ) +{ + mRefFont.setPointSizeF( d ); + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontCapitalsComboBox_currentIndexChanged( int index ) +{ + int capitalsindex = mFontCapitalsComboBox->itemData( index ).toUInt(); + mRefFont.setCapitalization(( QFont::Capitalization ) capitalsindex ); + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontFamilyCmbBx_currentFontChanged( const QFont& f ) +{ + mRefFont.setFamily( f.family() ); + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontStyleComboBox_currentIndexChanged( const QString & text ) +{ + QgsFontUtils::updateFontViaStyle( mRefFont, text ); + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontUnderlineBtn_toggled( bool ckd ) +{ + mRefFont.setUnderline( ckd ); + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontStrikethroughBtn_toggled( bool ckd ) +{ + mRefFont.setStrikeOut( ckd ); + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontWordSpacingSpinBox_valueChanged( double spacing ) +{ + mRefFont.setWordSpacing( spacing ); + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontLetterSpacingSpinBox_valueChanged( double spacing ) +{ + mRefFont.setLetterSpacing( QFont::AbsoluteSpacing, spacing ); + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontSizeUnitWidget_changed() +{ + // disable pixel size limiting for labels defined in points + if ( mFontSizeUnitWidget->unit() != QgsUnitTypes::RenderMapUnits ) + { + mFontLimitPixelChkBox->setChecked( false ); + } + else if ( mMinPixelLimit == 0 ) + { + // initial minimum trigger value set, turn on pixel size limiting by default + // for labels defined in map units (ignored after first settings save) + mFontLimitPixelChkBox->setChecked( true ); + } + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mFontMinPixelSpinBox_valueChanged( int px ) +{ + // ensure max font pixel size for map unit labels can't be lower than min + mFontMaxPixelSpinBox->setMinimum( px ); + mFontMaxPixelSpinBox->update(); +} + +void QgsTextFormatWidget::on_mFontMaxPixelSpinBox_valueChanged( int px ) +{ + // ensure max font pixel size for map unit labels can't be lower than min + if ( px < mFontMinPixelSpinBox->value() ) + { + mFontMaxPixelSpinBox->blockSignals( true ); + mFontMaxPixelSpinBox->setValue( mFontMinPixelSpinBox->value() ); + mFontMaxPixelSpinBox->blockSignals( false ); + } + mFontMaxPixelSpinBox->setMinimum( mFontMinPixelSpinBox->value() ); +} + +void QgsTextFormatWidget::on_mBufferUnitWidget_changed() +{ + updateFont( mRefFont ); +} + +void QgsTextFormatWidget::on_mCoordXDDBtn_dataDefinedActivated( bool active ) +{ + if ( !active ) //no data defined alignment without data defined position + { + enableDataDefinedAlignment( false ); + } + else if ( mCoordYDDBtn->isActive() ) + { + enableDataDefinedAlignment( true ); + } +} + +void QgsTextFormatWidget::on_mCoordYDDBtn_dataDefinedActivated( bool active ) +{ + if ( !active ) //no data defined alignment without data defined position + { + enableDataDefinedAlignment( false ); + } + else if ( mCoordXDDBtn->isActive() ) + { + enableDataDefinedAlignment( true ); + } +} + +void QgsTextFormatWidget::on_mShapeTypeCmbBx_currentIndexChanged( int index ) +{ + // shape background + bool isRect = (( QgsTextBackgroundSettings::ShapeType )index == QgsTextBackgroundSettings::ShapeRectangle + || ( QgsTextBackgroundSettings::ShapeType )index == QgsTextBackgroundSettings::ShapeSquare ); + bool isSVG = (( QgsTextBackgroundSettings::ShapeType )index == QgsTextBackgroundSettings::ShapeSVG ); + + showBackgroundPenStyle( isRect ); + showBackgroundRadius( isRect ); + + mShapeSVGPathFrame->setVisible( isSVG ); + // symbology SVG renderer only supports size^2 scaling, so we only use the x size spinbox + mShapeSizeYLabel->setVisible( !isSVG ); + mShapeSizeYSpnBx->setVisible( !isSVG ); + mShapeSizeYDDBtn->setVisible( !isSVG ); + mShapeSizeXLabel->setText( tr( "Size%1" ).arg( !isSVG ? tr( " X" ) : "" ) ); + + // SVG parameter setting doesn't support color's alpha component yet + mShapeFillColorBtn->setAllowAlpha( !isSVG ); + mShapeFillColorBtn->setButtonBackground(); + mShapeBorderColorBtn->setAllowAlpha( !isSVG ); + mShapeBorderColorBtn->setButtonBackground(); + + // configure SVG parameter widgets + mShapeSVGParamsBtn->setVisible( isSVG ); + if ( isSVG ) + { + updateSvgWidgets( mShapeSVGPathLineEdit->text() ); + } + else + { + mShapeFillColorLabel->setEnabled( true ); + mShapeFillColorBtn->setEnabled( true ); + mShapeFillColorDDBtn->setEnabled( true ); + mShapeBorderColorLabel->setEnabled( true ); + mShapeBorderColorBtn->setEnabled( true ); + mShapeBorderColorDDBtn->setEnabled( true ); + mShapeBorderWidthLabel->setEnabled( true ); + mShapeBorderWidthSpnBx->setEnabled( true ); + mShapeBorderWidthDDBtn->setEnabled( true ); + } + // TODO: fix overriding SVG symbol's border width units in QgsSvgCache + // currently broken, fall back to symbol units only + mShapeBorderWidthUnitWidget->setVisible( !isSVG ); + mShapeSVGUnitsLabel->setVisible( isSVG ); + mShapeBorderUnitsDDBtn->setEnabled( !isSVG ); +} + +void QgsTextFormatWidget::on_mShapeSVGPathLineEdit_textChanged( const QString& text ) +{ + updateSvgWidgets( text ); +} + +void QgsTextFormatWidget::updateLinePlacementOptions() +{ + int numOptionsChecked = ( chkLineAbove->isChecked() ? 1 : 0 ) + + ( chkLineBelow->isChecked() ? 1 : 0 ) + + ( chkLineOn->isChecked() ? 1 : 0 ); + + if ( numOptionsChecked == 1 ) + { + //prevent unchecking last option + chkLineAbove->setEnabled( !chkLineAbove->isChecked() ); + chkLineBelow->setEnabled( !chkLineBelow->isChecked() ); + chkLineOn->setEnabled( !chkLineOn->isChecked() ); + } + else + { + chkLineAbove->setEnabled( true ); + chkLineBelow->setEnabled( true ); + chkLineOn->setEnabled( true ); + } +} + +void QgsTextFormatWidget::onSubstitutionsChanged( const QgsStringReplacementCollection& substitutions ) +{ + mSubstitutions = substitutions; + emit widgetChanged(); +} + +void QgsTextFormatWidget::previewScaleChanged( double scale ) +{ + lblFontPreview->setScale( scale ); +} + +void QgsTextFormatWidget::updateSvgWidgets( const QString& svgPath ) +{ + if ( mShapeSVGPathLineEdit->text() != svgPath ) + { + mShapeSVGPathLineEdit->setText( svgPath ); + } + + QString resolvedPath = QgsSymbolLayerUtils::symbolNameToPath( svgPath ); + bool validSVG = !resolvedPath.isNull(); + + // draw red text for path field if invalid (path can't be resolved) + mShapeSVGPathLineEdit->setStyleSheet( QString( !validSVG ? "QLineEdit{ color: rgb(225, 0, 0); }" : "" ) ); + mShapeSVGPathLineEdit->setToolTip( !validSVG ? tr( "File not found" ) : resolvedPath ); + + QColor fill, outline; + double outlineWidth = 0.0; + bool fillParam = false, outlineParam = false, outlineWidthParam = false; + if ( validSVG ) + { + QgsSvgCache::instance()->containsParams( resolvedPath, fillParam, fill, outlineParam, outline, outlineWidthParam, outlineWidth ); + } + + mShapeSVGParamsBtn->setEnabled( validSVG && ( fillParam || outlineParam || outlineWidthParam ) ); + + mShapeFillColorLabel->setEnabled( validSVG && fillParam ); + mShapeFillColorBtn->setEnabled( validSVG && fillParam ); + mShapeFillColorDDBtn->setEnabled( validSVG && fillParam ); + if ( mLoadSvgParams && validSVG && fillParam ) + mShapeFillColorBtn->setColor( fill ); + + mShapeBorderColorLabel->setEnabled( validSVG && outlineParam ); + mShapeBorderColorBtn->setEnabled( validSVG && outlineParam ); + mShapeBorderColorDDBtn->setEnabled( validSVG && outlineParam ); + if ( mLoadSvgParams && validSVG && outlineParam ) + mShapeBorderColorBtn->setColor( outline ); + + mShapeBorderWidthLabel->setEnabled( validSVG && outlineWidthParam ); + mShapeBorderWidthSpnBx->setEnabled( validSVG && outlineWidthParam ); + mShapeBorderWidthDDBtn->setEnabled( validSVG && outlineWidthParam ); + if ( mLoadSvgParams && validSVG && outlineWidthParam ) + mShapeBorderWidthSpnBx->setValue( outlineWidth ); + + // TODO: fix overriding SVG symbol's border width units in QgsSvgCache + // currently broken, fall back to symbol's + //mShapeBorderWidthUnitWidget->setEnabled( validSVG && outlineWidthParam ); + //mShapeBorderUnitsDDBtn->setEnabled( validSVG && outlineWidthParam ); + mShapeSVGUnitsLabel->setEnabled( validSVG && outlineWidthParam ); +} + +void QgsTextFormatWidget::on_mShapeSVGSelectorBtn_clicked() +{ + QgsSvgSelectorDialog svgDlg( this ); + svgDlg.setWindowTitle( tr( "Select SVG file" ) ); + svgDlg.svgSelector()->setSvgPath( mShapeSVGPathLineEdit->text().trimmed() ); + + if ( svgDlg.exec() == QDialog::Accepted ) + { + QString svgPath = svgDlg.svgSelector()->currentSvgPath(); + if ( !svgPath.isEmpty() ) + { + mShapeSVGPathLineEdit->setText( svgPath ); + } + } +} + +void QgsTextFormatWidget::on_mShapeSVGParamsBtn_clicked() +{ + QString svgPath = mShapeSVGPathLineEdit->text(); + mLoadSvgParams = true; + updateSvgWidgets( svgPath ); + mLoadSvgParams = false; +} + +void QgsTextFormatWidget::on_mShapeRotationCmbBx_currentIndexChanged( int index ) +{ + mShapeRotationDblSpnBx->setEnabled(( QgsTextBackgroundSettings::RotationType )index != QgsTextBackgroundSettings::RotationSync ); + mShapeRotationDDBtn->setEnabled(( QgsTextBackgroundSettings::RotationType )index != QgsTextBackgroundSettings::RotationSync ); +} + +void QgsTextFormatWidget::on_mPreviewTextEdit_textChanged( const QString & text ) +{ + lblFontPreview->setText( text ); + updatePreview(); +} + +void QgsTextFormatWidget::on_mPreviewTextBtn_clicked() +{ + mPreviewTextEdit->setText( QString( "Lorem Ipsum" ) ); + updatePreview(); +} + +void QgsTextFormatWidget::on_mPreviewBackgroundBtn_colorChanged( const QColor &color ) +{ + setPreviewBackground( color ); +} + +void QgsTextFormatWidget::on_mDirectSymbLeftToolBtn_clicked() +{ + bool gotChar = false; + QChar dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ) ); + + if ( !gotChar ) + return; + + if ( !dirSymb.isNull() ) + mDirectSymbLeftLineEdit->setText( QString( dirSymb ) ); +} + +void QgsTextFormatWidget::on_mDirectSymbRightToolBtn_clicked() +{ + bool gotChar = false; + QChar dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ) ); + + if ( !gotChar ) + return; + + if ( !dirSymb.isNull() ) + mDirectSymbRightLineEdit->setText( QString( dirSymb ) ); +} + +void QgsTextFormatWidget::on_mChkNoObstacle_toggled( bool active ) +{ + mPolygonObstacleTypeFrame->setEnabled( active ); + mObstaclePriorityFrame->setEnabled( active ); +} + +void QgsTextFormatWidget::on_chkLineOrientationDependent_toggled( bool active ) +{ + if ( active ) + { + chkLineAbove->setText( tr( "Left of line" ) ); + chkLineBelow->setText( tr( "Right of line" ) ); + } + else + { + chkLineAbove->setText( tr( "Above line" ) ); + chkLineBelow->setText( tr( "Below line" ) ); + } +} + + +void QgsTextFormatWidget::on_mToolButtonConfigureSubstitutes_clicked() +{ + QgsPanelWidget* panel = QgsPanelWidget::findParentPanel( this ); + if ( panel && panel->dockMode() ) + { + QgsSubstitutionListWidget* widget = new QgsSubstitutionListWidget( panel ); + widget->setPanelTitle( tr( "Substitutions" ) ); + widget->setSubstitutions( mSubstitutions ); + connect( widget, SIGNAL( substitutionsChanged( QgsStringReplacementCollection ) ), this, SLOT( onSubstitutionsChanged( QgsStringReplacementCollection ) ) ); + panel->openPanel( widget ); + return; + } + + QgsSubstitutionListDialog dlg( this ); + dlg.setSubstitutions( mSubstitutions ); + if ( dlg.exec() == QDialog::Accepted ) + { + mSubstitutions = dlg.substitutions(); + emit widgetChanged(); + } +} + +void QgsTextFormatWidget::showBackgroundRadius( bool show ) +{ + mShapeRadiusLabel->setVisible( show ); + mShapeRadiusXDbSpnBx->setVisible( show ); + + mShapeRadiusYDbSpnBx->setVisible( show ); + + mShapeRadiusUnitWidget->setVisible( show ); + + mShapeRadiusDDBtn->setVisible( show ); + mShapeRadiusUnitsDDBtn->setVisible( show ); +} + +void QgsTextFormatWidget::showBackgroundPenStyle( bool show ) +{ + mShapePenStyleLabel->setVisible( show ); + mShapePenStyleCmbBx->setVisible( show ); + + mShapePenStyleDDBtn->setVisible( show ); +} + +void QgsTextFormatWidget::enableDataDefinedAlignment( bool enable ) +{ + mCoordAlignmentFrame->setEnabled( enable ); +} + + diff --git a/src/gui/qgstextformatwidget.h b/src/gui/qgstextformatwidget.h new file mode 100644 index 00000000000..d7d38d93784 --- /dev/null +++ b/src/gui/qgstextformatwidget.h @@ -0,0 +1,198 @@ +/*************************************************************************** + qgstextformatwidget.h + --------------------- + begin : June 2009 + copyright : (C) Martin Dobias + email : wonder dot sk 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 QGSTEXTFORMATWIDGET_H +#define QGSTEXTFORMATWIDGET_H + +#include +#include "qgstextrenderer.h" +#include "qgsstringutils.h" +#include + +class QgsMapCanvas; +class QgsCharacterSelectorDialog; + + +/** \class QgsTextFormatWidget + * \ingroup gui + * A widget for customising text formatting settings. + * + * QgsTextFormatWidget provides a widget for controlling the appearance of text rendered + * using QgsTextRenderer. The preview includes all settings contained within + * a QgsTextFormat, including shadow, background and buffer. + * + * Additionally, the widget can handle labeling settings due to the large overlap between + * the text renderer settings and the labeling settings. This mode is possible by + * subclassing QgsTextFormatWidget and calling the protected constructor with a mode + * of Labeling. + * + * @note Added in QGIS 3.0 + */ + +class GUI_EXPORT QgsTextFormatWidget : public QWidget, protected Ui::QgsTextFormatWidgetBase +{ + Q_OBJECT + Q_PROPERTY( QgsTextFormat format READ format ) + + public: + + /** Constructor for QgsTextFormatWidget. + * @param format initial formatting settings to show in widget + * @param mapCanvas associated map canvas + * @param parent parent widget + */ + QgsTextFormatWidget( const QgsTextFormat& format = QgsTextFormat(), QgsMapCanvas* mapCanvas = nullptr, QWidget* parent = nullptr ); + + ~QgsTextFormatWidget(); + + /** Returns the current formatting settings defined by the widget. + */ + QgsTextFormat format() const; + + public slots: + + /** Sets whether the widget should be shown in a compact dock mode. + * @param enabled set to true to show in dock mode. + */ + void setDockMode( bool enabled ); + + signals: + + //! Emitted when the text format defined by the widget changes + void widgetChanged(); + + protected: + + //! Widget mode + enum Mode + { + Text = 0, //!< Default mode, show text formatting settings only + Labeling, //!< Show labeling settings in addition to text formatting settings + }; + + /** Constructor for QgsTextFormatWidget. + * @param mapCanvas associated map canvas + * @param parent parent widget + * @param mode widget mode + */ + QgsTextFormatWidget( QgsMapCanvas* mapCanvas, QWidget* parent, Mode mode ); + + /** Updates the widget's state to reflect the settings in a QgsTextFormat. + * @param format source format + */ + void updateWidgetForFormat( const QgsTextFormat& format ); + + /** Sets the background color for the text preview widget. + * @param color background color + */ + void setPreviewBackground( const QColor& color ); + + /** Controls whether data defined alignment buttons are enabled. + * @param enable set to true to enable alignment controls + */ + void enableDataDefinedAlignment( bool enable ); + + //! Text substitution list + QgsStringReplacementCollection mSubstitutions; + //! Quadrant button group + QButtonGroup* mQuadrantBtnGrp; + //! Symbol direction button group + QButtonGroup* mDirectSymbBtnGrp; + //! Upside down labels button group + QButtonGroup* mUpsidedownBtnGrp; + //! Point placement button group + QButtonGroup* mPlacePointBtnGrp; + //! Line placement button group + QButtonGroup* mPlaceLineBtnGrp; + //! Polygon placement button group + QButtonGroup* mPlacePolygonBtnGrp; + //! Pixel size font limit + int mMinPixelLimit; + + protected slots: + + //! Updates line placement options to reflect current state of widget + void updateLinePlacementOptions(); + + //! Updates label placement options to reflect current state of widget + void updatePlacementWidgets(); + + private: + Mode mWidgetMode; + QgsMapCanvas* mMapCanvas; + QgsCharacterSelectorDialog* mCharDlg; + + QFontDatabase mFontDB; + + // background reference font + QFont mRefFont; + bool mDockMode; + + bool mLoadSvgParams; + + void initWidget(); + void setWidgetMode( Mode mode ); + void toggleDDButtons( bool visible ); + void blockFontChangeSignals( bool blk ); + void populateFontCapitalsComboBox(); + void populateFontStyleComboBox(); + void updateFont( const QFont& font ); + void connectValueChanged( const QList &widgets, const char* slot ); + + private slots: + void optionsStackedWidget_CurrentChanged( int indx ); + void showBackgroundRadius( bool show ); + void showBackgroundPenStyle( bool show ); + void on_mShapeSVGPathLineEdit_textChanged( const QString& text ); + void onSubstitutionsChanged( const QgsStringReplacementCollection& substitutions ); + void previewScaleChanged( double scale ); + void on_mFontSizeSpinBox_valueChanged( double d ); + void on_mFontCapitalsComboBox_currentIndexChanged( int index ); + void on_mFontFamilyCmbBx_currentFontChanged( const QFont& f ); + void on_mFontStyleComboBox_currentIndexChanged( const QString & text ); + void on_mFontUnderlineBtn_toggled( bool ckd ); + void on_mFontStrikethroughBtn_toggled( bool ckd ); + void on_mFontWordSpacingSpinBox_valueChanged( double spacing ); + void on_mFontLetterSpacingSpinBox_valueChanged( double spacing ); + void on_mFontSizeUnitWidget_changed(); + void on_mFontMinPixelSpinBox_valueChanged( int px ); + void on_mFontMaxPixelSpinBox_valueChanged( int px ); + void on_mBufferUnitWidget_changed(); + void on_mCoordXDDBtn_dataDefinedActivated( bool active ); + void on_mCoordYDDBtn_dataDefinedActivated( bool active ); + void on_mShapeTypeCmbBx_currentIndexChanged( int index ); + void on_mShapeRotationCmbBx_currentIndexChanged( int index ); + void on_mShapeSVGParamsBtn_clicked(); + void on_mShapeSVGSelectorBtn_clicked(); + void on_mPreviewTextEdit_textChanged( const QString & text ); + void on_mPreviewTextBtn_clicked(); + void on_mPreviewBackgroundBtn_colorChanged( const QColor &color ); + void on_mDirectSymbLeftToolBtn_clicked(); + void on_mDirectSymbRightToolBtn_clicked(); + void on_mChkNoObstacle_toggled( bool active ); + void on_chkLineOrientationDependent_toggled( bool active ); + void on_mToolButtonConfigureSubstitutes_clicked(); + void collapseSample( bool collapse ); + void changeTextColor( const QColor &color ); + void changeBufferColor( const QColor &color ); + void updatePreview(); + void scrollPreview(); + void updateSvgWidgets( const QString& svgPath ); +}; + +#endif //QGSTEXTFORMATWIDGET_H + + diff --git a/src/ui/qgslabelingguibase.ui b/src/ui/qgstextformatwidgetbase.ui similarity index 98% rename from src/ui/qgslabelingguibase.ui rename to src/ui/qgstextformatwidgetbase.ui index 32d69cce220..9cbbe5c2fe5 100644 --- a/src/ui/qgslabelingguibase.ui +++ b/src/ui/qgstextformatwidgetbase.ui @@ -1,7 +1,7 @@ - QgsLabelingGuiBase - + QgsTextFormatWidgetBase + 0 @@ -29,7 +29,7 @@ 6 - + @@ -335,7 +335,7 @@ QTabWidget::Rounded - 0 + 1 @@ -664,86 +664,6 @@ 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Available typeface styles - - - QComboBox::AdjustToContentsOnFirstShow - - - - - - - - - - 0 - 0 - - - - letter - - - - - - - - 0 - 0 - - - - Space in pixels or map units, relative to size unit choice - - - 4 - - - -1000.000000000000000 - - - 999999999.000000000000000 - - - 0.100000000000000 - - - true - - - - - - - ... - - - - - @@ -760,6 +680,51 @@ + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + + + + + + 0 + 0 + + + + Type case + + + + + + + true + + + Transparency + + + @@ -776,102 +741,13 @@ - - + + - ... + Spacing - - - - - - - 0 - 0 - - - - word - - - - - - - - 0 - 0 - - - - Space in pixels or map units, relative to size unit choice - - - 4 - - - -1000.000000000000000 - - - 999999999.000000000000000 - - - 0.100000000000000 - - - true - - - - - - - ... - - - - - - - - - - 0 - 0 - - - - Size - - - - - - - ... - - - - - - - ... - - - - - - - ... - - - - - - @@ -897,186 +773,7 @@ - - - - Spacing - - - - - - - - 0 - 0 - - - - Font - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - ... - - - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 120 - 16777215 - - - - - - - - - - - If enabled, the label text will automatically be modified using a preset list of substitutes - - - Apply label text substitutes - - - - - - - false - - - - - - - true - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Capitalization style of text - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - true - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - 100 - - - Qt::Horizontal - - - - - - - true - - - - 0 - 0 - - - - % - - - 100 - - - - - - - - - - true - - - Transparency - - - - - - - ... - - - - + @@ -1249,33 +946,33 @@ - - - - ... - - - - - - - ... + + + + + 0 + 0 + - - - - - - Blend mode + + + 0 + 0 + - - - - - - ... + + + 16777215 + 16777215 + + + + Available typeface styles + + + QComboBox::AdjustToContentsOnFirstShow @@ -1317,8 +1014,129 @@ font-style: italic; - - + + + + + + + + 0 + 0 + + + + Font + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + ... + + + + + + + ... + + + + + + + ... + + + + + + + ... + + + + + + + ... + + + + + + + ... + + + + + + + + + + ... + + + + + + + false + + + + + + + ... + + + + + + + Blend mode + + + + + + + true + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Capitalization style of text + + + + + + + ... + + + + + 0 @@ -1326,7 +1144,14 @@ font-style: italic; - Type case + Size + + + + + + + ... @@ -1343,19 +1168,221 @@ font-style: italic; - - - - false - - - Configure substitutes + + + + + 0 + 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + 100 + + + Qt::Horizontal + + + + + + + true + + + + 0 + 0 + + + + % + + + 100 + + + + + + + + ... + + + + + + + 0 + 0 + + + + word + + + + + + + + 0 + 0 + + + + Space in pixels or map units, relative to size unit choice + + + 4 + + + -1000.000000000000000 + + + 999999999.000000000000000 + + + 0.100000000000000 + + + true + + + + + + + + + + + + 0 + 0 + + + + letter + + + + + + + + 0 + 0 + + + + Space in pixels or map units, relative to size unit choice + + + 4 + + + -1000.000000000000000 + + + 999999999.000000000000000 + + + 0.100000000000000 + + + true + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + If enabled, the label text will automatically be modified using a preset list of substitutes + + + Apply label text substitutes + + + + + + + false + + + Configure substitutes + + + ... + + + + + + @@ -6292,9 +6319,9 @@ font-style: italic; - + - + 0 @@ -6412,6 +6439,12 @@ font-style: italic; QWidget
qgsscalewidget.h
+ + QgsPanelWidget + QWidget +
qgspanelwidget.h
+ 1 +
scrollArea_mPreview @@ -6431,7 +6464,6 @@ font-style: italic; mFontBoldBtn mFontBoldDDBtn mFontItalicBtn - mFontItalicDDBtn mFontSizeSpinBox mFontSizeDDBtn mFontUnitsDDBtn @@ -6443,9 +6475,7 @@ font-style: italic; mFontCapitalsComboBox mFontCaseDDBtn mFontLetterSpacingSpinBox - mFontLetterSpacingDDBtn mFontWordSpacingSpinBox - mFontWordSpacingDDBtn comboBlendMode mFontBlendModeDDBtn scrollArea_5 diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt index 8bdada70b97..8067b428e33 100644 --- a/tests/src/python/CMakeLists.txt +++ b/tests/src/python/CMakeLists.txt @@ -104,6 +104,7 @@ ADD_PYTHON_TEST(PyQgsSyntacticSugar test_syntactic_sugar.py) ADD_PYTHON_TEST(PyQgsStringUtils test_qgsstringutils.py) ADD_PYTHON_TEST(PyQgsSymbol test_qgssymbol.py) ADD_PYTHON_TEST(PyQgsSymbolLayerUtils test_qgssymbollayerutils.py) +ADD_PYTHON_TEST(PyQgsTextFormatWidget test_qgstextformatwidget.py) ADD_PYTHON_TEST(PyQgsTreeWidgetItem test_qgstreewidgetitem.py) ADD_PYTHON_TEST(PyQgsUnitTypes test_qgsunittypes.py) ADD_PYTHON_TEST(PyQgsVectorColorRamp test_qgsvectorcolorramp.py) diff --git a/tests/src/python/test_qgstextformatwidget.py b/tests/src/python/test_qgstextformatwidget.py new file mode 100644 index 00000000000..f8b3b3673fe --- /dev/null +++ b/tests/src/python/test_qgstextformatwidget.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +"""QGIS Unit tests for QgsTextFormatWidget. + +.. note:: 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. +""" +__author__ = 'Nyall Dawson' +__date__ = '2016-09' +__copyright__ = 'Copyright 2016, The QGIS Project' +# This will get replaced with a git SHA1 when you do a git archive +__revision__ = '$Format:%H$' + +import qgis # NOQA +import os + +from qgis.core import (QgsTextBufferSettings, + QgsTextBackgroundSettings, + QgsTextShadowSettings, + QgsTextFormat, + QgsUnitTypes, + QgsMapUnitScale) +from qgis.gui import (QgsTextFormatWidget) +from qgis.PyQt.QtGui import (QColor, QPainter, QFont, QImage, QBrush, QPen) +from qgis.PyQt.QtCore import (Qt, QSizeF, QPointF, QRectF, QDir) +from qgis.testing import unittest, start_app +from utilities import getTestFont, svgSymbolsPath + +start_app() + + +class PyQgsTextFormatWidget(unittest.TestCase): + + def createBufferSettings(self): + s = QgsTextBufferSettings() + s.setEnabled(True) + s.setSize(5) + s.setSizeUnit(QgsUnitTypes.RenderPixels) + s.setSizeMapUnitScale(QgsMapUnitScale(1, 2)) + s.setColor(QColor(255, 0, 0)) + s.setFillBufferInterior(True) + s.setOpacity(0.5) + s.setJoinStyle(Qt.RoundJoin) + s.setBlendMode(QPainter.CompositionMode_Difference) + return s + + def checkBufferSettings(self, s): + """ test QgsTextBufferSettings """ + self.assertTrue(s.enabled()) + self.assertEqual(s.size(), 5) + self.assertEqual(s.sizeUnit(), QgsUnitTypes.RenderPixels) + self.assertEqual(s.sizeMapUnitScale(), QgsMapUnitScale(1, 2)) + self.assertEqual(s.color(), QColor(255, 0, 0)) + self.assertTrue(s.fillBufferInterior()) + self.assertEqual(s.opacity(), 0.5) + self.assertEqual(s.joinStyle(), Qt.RoundJoin) + self.assertEqual(s.blendMode(), QPainter.CompositionMode_Difference) + + def createBackgroundSettings(self): + s = QgsTextBackgroundSettings() + s.setEnabled(True) + s.setType(QgsTextBackgroundSettings.ShapeEllipse) + s.setSvgFile('svg.svg') + s.setSizeType(QgsTextBackgroundSettings.SizeFixed) + s.setSize(QSizeF(1, 2)) + s.setSizeUnit(QgsUnitTypes.RenderPixels) + s.setSizeMapUnitScale(QgsMapUnitScale(1, 2)) + s.setRotationType(QgsTextBackgroundSettings.RotationFixed) + s.setRotation(45) + s.setOffset(QPointF(3, 4)) + s.setOffsetUnit(QgsUnitTypes.RenderMapUnits) + s.setOffsetMapUnitScale(QgsMapUnitScale(5, 6)) + s.setRadii(QSizeF(11, 12)) + s.setRadiiUnit(QgsUnitTypes.RenderPixels) + s.setRadiiMapUnitScale(QgsMapUnitScale(15, 16)) + s.setFillColor(QColor(255, 0, 0)) + s.setBorderColor(QColor(0, 255, 0)) + s.setOpacity(0.5) + s.setJoinStyle(Qt.RoundJoin) + s.setBlendMode(QPainter.CompositionMode_Difference) + s.setBorderWidth(7) + s.setBorderWidthUnit(QgsUnitTypes.RenderMapUnits) + s.setBorderWidthMapUnitScale(QgsMapUnitScale(QgsMapUnitScale(25, 26))) + return s + + def checkBackgroundSettings(self, s): + """ test QgsTextBackgroundSettings """ + self.assertTrue(s.enabled()) + self.assertEqual(s.type(), QgsTextBackgroundSettings.ShapeEllipse) + self.assertEqual(s.svgFile(), 'svg.svg') + self.assertEqual(s.sizeType(), QgsTextBackgroundSettings.SizeFixed) + self.assertEqual(s.size(), QSizeF(1, 2)) + self.assertEqual(s.sizeUnit(), QgsUnitTypes.RenderPixels) + self.assertEqual(s.sizeMapUnitScale(), QgsMapUnitScale(1, 2)) + self.assertEqual(s.rotationType(), QgsTextBackgroundSettings.RotationFixed) + self.assertEqual(s.rotation(), 45) + self.assertEqual(s.offset(), QPointF(3, 4)) + self.assertEqual(s.offsetUnit(), QgsUnitTypes.RenderMapUnits) + self.assertEqual(s.offsetMapUnitScale(), QgsMapUnitScale(5, 6)) + self.assertEqual(s.radii(), QSizeF(11, 12)) + self.assertEqual(s.radiiUnit(), QgsUnitTypes.RenderPixels) + self.assertEqual(s.radiiMapUnitScale(), QgsMapUnitScale(15, 16)) + self.assertEqual(s.fillColor(), QColor(255, 0, 0)) + self.assertEqual(s.borderColor(), QColor(0, 255, 0)) + self.assertEqual(s.opacity(), 0.5) + self.assertEqual(s.joinStyle(), Qt.RoundJoin) + self.assertEqual(s.blendMode(), QPainter.CompositionMode_Difference) + self.assertEqual(s.borderWidth(), 7) + self.assertEqual(s.borderWidthUnit(), QgsUnitTypes.RenderMapUnits) + self.assertEqual(s.borderWidthMapUnitScale(), QgsMapUnitScale(25, 26)) + + def createShadowSettings(self): + s = QgsTextShadowSettings() + s.setEnabled(True) + s.setShadowPlacement(QgsTextShadowSettings.ShadowBuffer) + s.setOffsetAngle(45) + s.setOffsetDistance(75) + s.setOffsetUnit(QgsUnitTypes.RenderMapUnits) + s.setOffsetMapUnitScale(QgsMapUnitScale(5, 6)) + s.setOffsetGlobal(True) + s.setBlurRadius(11) + s.setBlurRadiusUnit(QgsUnitTypes.RenderMapUnits) + s.setBlurRadiusMapUnitScale(QgsMapUnitScale(15, 16)) + s.setBlurAlphaOnly(True) + s.setColor(QColor(255, 0, 0)) + s.setOpacity(0.5) + s.setScale(123) + s.setBlendMode(QPainter.CompositionMode_Difference) + return s + + def checkShadowSettings(self, s): + """ test QgsTextShadowSettings """ + self.assertTrue(s.enabled()) + self.assertEqual(s.shadowPlacement(), QgsTextShadowSettings.ShadowBuffer) + self.assertEqual(s.offsetAngle(), 45) + self.assertEqual(s.offsetDistance(), 75) + self.assertEqual(s.offsetUnit(), QgsUnitTypes.RenderMapUnits) + self.assertEqual(s.offsetMapUnitScale(), QgsMapUnitScale(5, 6)) + self.assertTrue(s.offsetGlobal()) + self.assertEqual(s.blurRadius(), 11) + self.assertEqual(s.blurRadiusUnit(), QgsUnitTypes.RenderMapUnits) + self.assertEqual(s.blurRadiusMapUnitScale(), QgsMapUnitScale(15, 16)) + self.assertTrue(s.blurAlphaOnly()) + self.assertEqual(s.color(), QColor(255, 0, 0)) + self.assertEqual(s.opacity(), 0.5) + self.assertEqual(s.scale(), 123) + self.assertEqual(s.blendMode(), QPainter.CompositionMode_Difference) + + def createFormatSettings(self): + s = QgsTextFormat() + s.setBuffer(self.createBufferSettings()) + s.setBackground(self.createBackgroundSettings()) + s.setShadow(self.createShadowSettings()) + s.setFont(getTestFont()) + s.setNamedStyle('Roman') + s.setSize(5) + s.setSizeUnit(QgsUnitTypes.RenderPoints) + s.setSizeMapUnitScale(QgsMapUnitScale(1, 2)) + s.setColor(QColor(255, 0, 0)) + s.setOpacity(0.5) + s.setBlendMode(QPainter.CompositionMode_Difference) + s.setLineHeight(5) + return s + + def checkTextFormat(self, s): + """ test QgsTextFormat """ + self.checkBufferSettings(s.buffer()) + self.checkShadowSettings(s.shadow()) + self.checkBackgroundSettings(s.background()) + self.assertEqual(s.font().family(), 'QGIS Vera Sans') + self.assertEqual(s.namedStyle(), 'Roman') + self.assertEqual(s.size(), 5) + self.assertEqual(s.sizeUnit(), QgsUnitTypes.RenderPoints) + self.assertEqual(s.sizeMapUnitScale(), QgsMapUnitScale(1, 2)) + self.assertEqual(s.color(), QColor(255, 0, 0)) + self.assertEqual(s.opacity(), 0.5) + self.assertEqual(s.blendMode(), QPainter.CompositionMode_Difference) + self.assertEqual(s.lineHeight(), 5) + + def testSettings(self): + # test that widget correctly sets and returns matching settings + s = self.createFormatSettings() + w = QgsTextFormatWidget(s) + self.checkTextFormat(w.format()) + + +if __name__ == '__main__': + unittest.main()