QGIS API Documentation  3.6.0-Noosa (5873452)
qgstextformatwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstextformatwidget.h
3  ---------------------
4  begin : June 2009
5  copyright : (C) Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgstextformatwidget.h"
17 #include "qgsmapcanvas.h"
19 #include "qgslogger.h"
20 #include "qgsfontutils.h"
21 #include "qgssymbollayerutils.h"
22 #include "qgssvgcache.h"
23 #include "qgssvgselectorwidget.h"
25 #include "qgspallabeling.h" // for enum values
26 #include "qgspathresolver.h"
27 #include "qgsproject.h"
28 #include "qgssettings.h"
29 #include "qgseffectstack.h"
30 #include "qgspainteffectregistry.h"
31 
32 #include <QButtonGroup>
33 
34 QgsTextFormatWidget::QgsTextFormatWidget( const QgsTextFormat &format, QgsMapCanvas *mapCanvas, QWidget *parent )
35  : QWidget( parent )
36  , mMapCanvas( mapCanvas )
37 {
38  initWidget();
39  setWidgetMode( Text );
40  updateWidgetForFormat( format );
41 }
42 
43 QgsTextFormatWidget::QgsTextFormatWidget( QgsMapCanvas *mapCanvas, QWidget *parent, Mode mode )
44  : QWidget( parent )
45  , mWidgetMode( mode )
46  , mMapCanvas( mapCanvas )
47 {
48  initWidget();
49  setWidgetMode( mode );
50 }
51 
52 void QgsTextFormatWidget::initWidget()
53 {
54  setupUi( this );
55  connect( mShapeSVGPathLineEdit, &QLineEdit::textChanged, this, &QgsTextFormatWidget::mShapeSVGPathLineEdit_textChanged );
56  connect( mFontSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontSizeSpinBox_valueChanged );
57  connect( mFontCapitalsComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::mFontCapitalsComboBox_currentIndexChanged );
58  connect( mFontFamilyCmbBx, &QFontComboBox::currentFontChanged, this, &QgsTextFormatWidget::mFontFamilyCmbBx_currentFontChanged );
59  connect( mFontStyleComboBox, static_cast<void ( QComboBox::* )( const QString & )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::mFontStyleComboBox_currentIndexChanged );
60  connect( mFontUnderlineBtn, &QToolButton::toggled, this, &QgsTextFormatWidget::mFontUnderlineBtn_toggled );
61  connect( mFontStrikethroughBtn, &QToolButton::toggled, this, &QgsTextFormatWidget::mFontStrikethroughBtn_toggled );
62  connect( mFontWordSpacingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontWordSpacingSpinBox_valueChanged );
63  connect( mFontLetterSpacingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontLetterSpacingSpinBox_valueChanged );
64  connect( mFontSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsTextFormatWidget::mFontSizeUnitWidget_changed );
65  connect( mFontMinPixelSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontMinPixelSpinBox_valueChanged );
66  connect( mFontMaxPixelSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontMaxPixelSpinBox_valueChanged );
67  connect( mBufferUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsTextFormatWidget::mBufferUnitWidget_changed );
68  connect( mCoordXDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::mCoordXDDBtn_activated );
69  connect( mCoordYDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::mCoordYDDBtn_activated );
70  connect( mShapeTypeCmbBx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::mShapeTypeCmbBx_currentIndexChanged );
71  connect( mShapeRotationCmbBx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::mShapeRotationCmbBx_currentIndexChanged );
72  connect( mShapeSVGParamsBtn, &QPushButton::clicked, this, &QgsTextFormatWidget::mShapeSVGParamsBtn_clicked );
73  connect( mShapeSVGSelectorBtn, &QPushButton::clicked, this, &QgsTextFormatWidget::mShapeSVGSelectorBtn_clicked );
74  connect( mPreviewTextEdit, &QLineEdit::textChanged, this, &QgsTextFormatWidget::mPreviewTextEdit_textChanged );
75  connect( mPreviewTextBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mPreviewTextBtn_clicked );
76  connect( mPreviewBackgroundBtn, &QgsColorButton::colorChanged, this, &QgsTextFormatWidget::mPreviewBackgroundBtn_colorChanged );
77  connect( mDirectSymbLeftToolBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mDirectSymbLeftToolBtn_clicked );
78  connect( mDirectSymbRightToolBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mDirectSymbRightToolBtn_clicked );
79  connect( mChkNoObstacle, &QCheckBox::toggled, this, &QgsTextFormatWidget::mChkNoObstacle_toggled );
80  connect( chkLineOrientationDependent, &QCheckBox::toggled, this, &QgsTextFormatWidget::chkLineOrientationDependent_toggled );
81  connect( mToolButtonConfigureSubstitutes, &QToolButton::clicked, this, &QgsTextFormatWidget::mToolButtonConfigureSubstitutes_clicked );
82 
83  const int iconSize = QgsGuiUtils::scaleIconSize( 20 );
84  mOptionsTab->setIconSize( QSize( iconSize, iconSize ) );
85  const int iconSize32 = QgsGuiUtils::scaleIconSize( 32 );
86  const int iconSize24 = QgsGuiUtils::scaleIconSize( 24 );
87  const int iconSize18 = QgsGuiUtils::scaleIconSize( 18 );
88  mPointOffsetAboveLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
89  mPointOffsetAbove->setIconSize( QSize( iconSize32, iconSize18 ) );
90  mPointOffsetAboveRight->setIconSize( QSize( iconSize32, iconSize18 ) );
91  mPointOffsetLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
92  mPointOffsetOver ->setIconSize( QSize( iconSize32, iconSize18 ) );
93  mPointOffsetRight->setIconSize( QSize( iconSize32, iconSize18 ) );
94  mPointOffsetBelowLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
95  mPointOffsetBelow->setIconSize( QSize( iconSize32, iconSize18 ) );
96  mPointOffsetBelowRight->setIconSize( QSize( iconSize32, iconSize18 ) );
97  mLabelMinScale->setPixmap( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomOut.svg" ) ).pixmap( QSize( iconSize24, iconSize24 ) ) );
98  mLabelMaxScale->setPixmap( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomIn.svg" ) ).pixmap( QSize( iconSize24, iconSize24 ) ) );
99 
100  const int buttonSize = QgsGuiUtils::scaleIconSize( 24 );
101  mFontUnderlineBtn->setMinimumSize( buttonSize, buttonSize );
102  mFontUnderlineBtn->setMaximumSize( buttonSize, buttonSize );
103  mFontStrikethroughBtn->setMinimumSize( buttonSize, buttonSize );
104  mFontStrikethroughBtn->setMaximumSize( buttonSize, buttonSize );
105  mFontBoldBtn->setMinimumSize( buttonSize, buttonSize );
106  mFontBoldBtn->setMaximumSize( buttonSize, buttonSize );
107  mFontItalicBtn->setMinimumSize( buttonSize, buttonSize );
108  mFontItalicBtn->setMaximumSize( buttonSize, buttonSize );
109 
110  mPreviewScaleComboBox->setMapCanvas( mMapCanvas );
111  mPreviewScaleComboBox->setShowCurrentScaleButton( true );
112  connect( mPreviewScaleComboBox, &QgsScaleWidget::scaleChanged, this, &QgsTextFormatWidget::previewScaleChanged );
113 
114  Q_FOREACH ( QgsUnitSelectionWidget *unitWidget, findChildren<QgsUnitSelectionWidget *>() )
115  {
116  unitWidget->setMapCanvas( mMapCanvas );
117  }
141 
142  mFontLineHeightSpinBox->setClearValue( 1.0 );
143  mShapeRotationDblSpnBx->setClearValue( 0.0 );
144  mShapeOffsetXSpnBx->setClearValue( 0.0 );
145  mShapeOffsetYSpnBx->setClearValue( 0.0 );
146  mPointOffsetXSpinBox->setClearValue( 0.0 );
147  mPointOffsetYSpinBox->setClearValue( 0.0 );
148  mPointAngleSpinBox->setClearValue( 0.0 );
149  mFontLetterSpacingSpinBox->setClearValue( 0.0 );
150  mFontWordSpacingSpinBox->setClearValue( 0.0 );
151  mZIndexSpinBox->setClearValue( 0.0 );
152 
153  mObstacleTypeComboBox->addItem( tr( "Over the feature's interior" ), QgsPalLayerSettings::PolygonInterior );
154  mObstacleTypeComboBox->addItem( tr( "Over the feature's boundary" ), QgsPalLayerSettings::PolygonBoundary );
155 
156  mOffsetTypeComboBox->addItem( tr( "From point" ), QgsPalLayerSettings::FromPoint );
157  mOffsetTypeComboBox->addItem( tr( "From symbol bounds" ), QgsPalLayerSettings::FromSymbolBounds );
158 
159  mCharDlg = new QgsCharacterSelectorDialog( this );
160 
161  mRefFont = lblFontPreview->font();
162 
163  // internal connections
164  connect( mShadowOffsetAngleDial, &QAbstractSlider::valueChanged, mShadowOffsetAngleSpnBx, &QSpinBox::setValue );
165  connect( mShadowOffsetAngleSpnBx, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), mShadowOffsetAngleDial, &QAbstractSlider::setValue );
166  connect( mLimitLabelChkBox, &QAbstractButton::toggled, mLimitLabelSpinBox, &QWidget::setEnabled );
167  connect( mCheckBoxSubstituteText, &QAbstractButton::toggled, mToolButtonConfigureSubstitutes, &QWidget::setEnabled );
168 
169  //connections to prevent users removing all line placement positions
170  connect( chkLineAbove, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
171  connect( chkLineBelow, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
172  connect( chkLineOn, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
173 
174  populateFontCapitalsComboBox();
175 
176  // color buttons
177  mPreviewBackgroundBtn->setColorDialogTitle( tr( "Select Fill Color" ) );
178  mPreviewBackgroundBtn->setContext( QStringLiteral( "labeling" ) );
179  mPreviewBackgroundBtn->setColor( QColor( 255, 255, 255 ) );
180  btnTextColor->setColorDialogTitle( tr( "Select Text Color" ) );
181  btnTextColor->setContext( QStringLiteral( "labeling" ) );
182  btnTextColor->setDefaultColor( Qt::black );
183  btnBufferColor->setColorDialogTitle( tr( "Select Buffer Color" ) );
184  btnBufferColor->setContext( QStringLiteral( "labeling" ) );
185  btnBufferColor->setDefaultColor( Qt::white );
186  mShapeStrokeColorBtn->setColorDialogTitle( tr( "Select Stroke Color" ) );
187  mShapeStrokeColorBtn->setContext( QStringLiteral( "labeling" ) );
188  mShapeFillColorBtn->setColorDialogTitle( tr( "Select Fill Color" ) );
189  mShapeFillColorBtn->setContext( QStringLiteral( "labeling" ) );
190  mShadowColorBtn->setColorDialogTitle( tr( "Select Shadow Color" ) );
191  mShadowColorBtn->setContext( QStringLiteral( "labeling" ) );
192  mShadowColorBtn->setDefaultColor( Qt::black );
193 
194  mFontColorDDBtn->registerLinkedWidget( btnTextColor );
195  mBufferColorDDBtn->registerLinkedWidget( btnBufferColor );
196  mShapeStrokeColorDDBtn->registerLinkedWidget( mShapeStrokeColorBtn );
197  mShapeFillColorDDBtn->registerLinkedWidget( mShapeFillColorBtn );
198  mShadowColorDDBtn->registerLinkedWidget( mShadowColorBtn );
199 
200  // set up quadrant offset button group
201  mQuadrantBtnGrp = new QButtonGroup( this );
202  mQuadrantBtnGrp->addButton( mPointOffsetAboveLeft, static_cast<int>( QgsPalLayerSettings::QuadrantAboveLeft ) );
203  mQuadrantBtnGrp->addButton( mPointOffsetAbove, static_cast<int>( QgsPalLayerSettings::QuadrantAbove ) );
204  mQuadrantBtnGrp->addButton( mPointOffsetAboveRight, static_cast<int>( QgsPalLayerSettings::QuadrantAboveRight ) );
205  mQuadrantBtnGrp->addButton( mPointOffsetLeft, static_cast<int>( QgsPalLayerSettings::QuadrantLeft ) );
206  mQuadrantBtnGrp->addButton( mPointOffsetOver, static_cast<int>( QgsPalLayerSettings::QuadrantOver ) );
207  mQuadrantBtnGrp->addButton( mPointOffsetRight, static_cast<int>( QgsPalLayerSettings::QuadrantRight ) );
208  mQuadrantBtnGrp->addButton( mPointOffsetBelowLeft, static_cast<int>( QgsPalLayerSettings::QuadrantBelowLeft ) );
209  mQuadrantBtnGrp->addButton( mPointOffsetBelow, static_cast<int>( QgsPalLayerSettings::QuadrantBelow ) );
210  mQuadrantBtnGrp->addButton( mPointOffsetBelowRight, static_cast<int>( QgsPalLayerSettings::QuadrantBelowRight ) );
211  mQuadrantBtnGrp->setExclusive( true );
212 
213  // setup direction symbol(s) button group
214  mDirectSymbBtnGrp = new QButtonGroup( this );
215  mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnLR, static_cast<int>( QgsPalLayerSettings::SymbolLeftRight ) );
216  mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnAbove, static_cast<int>( QgsPalLayerSettings::SymbolAbove ) );
217  mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnBelow, static_cast<int>( QgsPalLayerSettings::SymbolBelow ) );
218  mDirectSymbBtnGrp->setExclusive( true );
219 
220  // upside-down labels button group
221  mUpsidedownBtnGrp = new QButtonGroup( this );
222  mUpsidedownBtnGrp->addButton( mUpsidedownRadioOff, static_cast<int>( QgsPalLayerSettings::Upright ) );
223  mUpsidedownBtnGrp->addButton( mUpsidedownRadioDefined, static_cast<int>( QgsPalLayerSettings::ShowDefined ) );
224  mUpsidedownBtnGrp->addButton( mUpsidedownRadioAll, static_cast<int>( QgsPalLayerSettings::ShowAll ) );
225  mUpsidedownBtnGrp->setExclusive( true );
226 
227  //mShapeCollisionsChkBx->setVisible( false ); // until implemented
228 
229  // post updatePlacementWidgets() connections
230  connect( chkLineAbove, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updatePlacementWidgets );
231  connect( chkLineBelow, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updatePlacementWidgets );
232 
233  // setup point placement button group
234  mPlacePointBtnGrp = new QButtonGroup( this );
235  mPlacePointBtnGrp->addButton( radPredefinedOrder, static_cast<int>( QgsPalLayerSettings::OrderedPositionsAroundPoint ) );
236  mPlacePointBtnGrp->addButton( radAroundPoint, static_cast<int>( QgsPalLayerSettings::AroundPoint ) );
237  mPlacePointBtnGrp->addButton( radOverPoint, static_cast<int>( QgsPalLayerSettings::OverPoint ) );
238  mPlacePointBtnGrp->setExclusive( true );
239  connect( mPlacePointBtnGrp, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ), this, &QgsTextFormatWidget::updatePlacementWidgets );
240 
241  // setup line placement button group (assigned enum id currently unused)
242  mPlaceLineBtnGrp = new QButtonGroup( this );
243  mPlaceLineBtnGrp->addButton( radLineParallel, static_cast<int>( QgsPalLayerSettings::Line ) );
244  mPlaceLineBtnGrp->addButton( radLineCurved, static_cast<int>( QgsPalLayerSettings::Curved ) );
245  mPlaceLineBtnGrp->addButton( radLineHorizontal, static_cast<int>( QgsPalLayerSettings::Horizontal ) );
246  mPlaceLineBtnGrp->setExclusive( true );
247  connect( mPlaceLineBtnGrp, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ), this, &QgsTextFormatWidget::updatePlacementWidgets );
248 
249  // setup polygon placement button group (assigned enum id currently unused)
250  mPlacePolygonBtnGrp = new QButtonGroup( this );
251  mPlacePolygonBtnGrp->addButton( radOverCentroid, static_cast<int>( QgsPalLayerSettings::OverPoint ) );
252  mPlacePolygonBtnGrp->addButton( radAroundCentroid, static_cast<int>( QgsPalLayerSettings::AroundPoint ) );
253  mPlacePolygonBtnGrp->addButton( radPolygonHorizontal, static_cast<int>( QgsPalLayerSettings::Horizontal ) );
254  mPlacePolygonBtnGrp->addButton( radPolygonFree, static_cast<int>( QgsPalLayerSettings::Free ) );
255  mPlacePolygonBtnGrp->addButton( radPolygonPerimeter, static_cast<int>( QgsPalLayerSettings::Line ) );
256  mPlacePolygonBtnGrp->addButton( radPolygonPerimeterCurved, static_cast<int>( QgsPalLayerSettings::PerimeterCurved ) );
257  mPlacePolygonBtnGrp->setExclusive( true );
258  connect( mPlacePolygonBtnGrp, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ), this, &QgsTextFormatWidget::updatePlacementWidgets );
259 
260  // Global settings group for groupboxes' saved/restored collapsed state
261  // maintains state across different dialogs
262  Q_FOREACH ( QgsCollapsibleGroupBox *grpbox, findChildren<QgsCollapsibleGroupBox *>() )
263  {
264  grpbox->setSettingGroup( QStringLiteral( "mAdvLabelingDlg" ) );
265  }
266 
267  connect( groupBox_mPreview,
269  this,
270  &QgsTextFormatWidget::collapseSample );
271 
272  // get rid of annoying outer focus rect on Mac
273  mLabelingOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect, false );
274 
275  QgsSettings settings;
276 
277  // reset horiz stretch of left side of options splitter (set to 1 for previewing in Qt Designer)
278  QSizePolicy policy( mLabelingOptionsListFrame->sizePolicy() );
279  policy.setHorizontalStretch( 0 );
280  mLabelingOptionsListFrame->setSizePolicy( policy );
281  if ( !settings.contains( QStringLiteral( "/Windows/Labeling/OptionsSplitState" ) ) )
282  {
283  // set left list widget width on initial showing
284  QList<int> splitsizes;
285  splitsizes << 115;
286  mLabelingOptionsSplitter->setSizes( splitsizes );
287  }
288 
289  // set up reverse connection from stack to list
290  connect( mLabelStackedWidget, &QStackedWidget::currentChanged, this, &QgsTextFormatWidget::optionsStackedWidget_CurrentChanged );
291 
292  // restore dialog, splitters and current tab
293  mFontPreviewSplitter->restoreState( settings.value( QStringLiteral( "Windows/Labeling/FontPreviewSplitState" ) ).toByteArray() );
294  mLabelingOptionsSplitter->restoreState( settings.value( QStringLiteral( "Windows/Labeling/OptionsSplitState" ) ).toByteArray() );
295 
296  mLabelingOptionsListWidget->setCurrentRow( settings.value( QStringLiteral( "Windows/Labeling/Tab" ), 0 ).toInt() );
297 
298  mBufferEffect.reset( QgsPaintEffectRegistry::defaultStack() );
299  connect( mBufferEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
300  mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );
301  mBackgroundEffect.reset( QgsPaintEffectRegistry::defaultStack() );
302  connect( mBackgroundEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
303  mBackgroundEffectWidget->setPaintEffect( mBackgroundEffect.get() );
304 
305  setDockMode( false );
306 
307 
308  QList<QWidget *> widgets;
309  widgets << btnBufferColor
310  << btnTextColor
311  << chkLabelPerFeaturePart
312  << chkLineAbove
313  << chkLineBelow
314  << chkLineOn
315  << chkLineOrientationDependent
316  << chkMergeLines
317  << chkPreserveRotation
318  << comboBlendMode
319  << comboBufferBlendMode
320  << mAlwaysShowDDBtn
321  << mBufferBlendModeDDBtn
322  << mBufferColorDDBtn
323  << mBufferDrawChkBx
324  << mBufferDrawDDBtn
325  << mBufferJoinStyleComboBox
326  << mBufferJoinStyleDDBtn
327  << mBufferSizeDDBtn
328  << mBufferOpacityDDBtn
329  << mBufferTranspFillChbx
330  << mBufferOpacityWidget
331  << mBufferUnitsDDBtn
332  << mCentroidDDBtn
333  << mCentroidInsideCheckBox
334  << mChkNoObstacle
335  << mCoordAlignmentHDDBtn
336  << mCoordAlignmentVDDBtn
337  << mCoordRotationDDBtn
338  << mCoordXDDBtn
339  << mCoordYDDBtn
340  << mDirectSymbChkBx
341  << mDirectSymbDDBtn
342  << mDirectSymbLeftDDBtn
343  << mDirectSymbLeftLineEdit
344  << mDirectSymbPlacementDDBtn
345  << mDirectSymbRevChkBx
346  << mDirectSymbRevDDBtn
347  << mDirectSymbRightDDBtn
348  << mDirectSymbRightLineEdit
349  << mFitInsidePolygonCheckBox
350  << mFontBlendModeDDBtn
351  << mFontBoldDDBtn
352  << mFontCapitalsComboBox
353  << mFontCaseDDBtn
354  << mFontColorDDBtn
355  << mFontDDBtn
356  << mFontItalicDDBtn
357  << mFontLetterSpacingDDBtn
358  << mFontLetterSpacingSpinBox
359  << mFontLimitPixelChkBox
360  << mFontLimitPixelDDBtn
361  << mFontLineHeightDDBtn
362  << mFontLineHeightSpinBox
363  << mFontMaxPixelDDBtn
364  << mFontMaxPixelSpinBox
365  << mFontMinPixelDDBtn
366  << mFontMinPixelSpinBox
367  << mFontMultiLineAlignComboBox
368  << mFontMultiLineAlignDDBtn
369  << mFontSizeDDBtn
370  << mFontSizeSpinBox
371  << mFontStrikeoutDDBtn
372  << mFontStyleComboBox
373  << mFontStyleDDBtn
374  << mFontOpacityDDBtn
375  << mTextOpacityWidget
376  << mFontUnderlineDDBtn
377  << mFontUnitsDDBtn
378  << mFontWordSpacingDDBtn
379  << mFontWordSpacingSpinBox
380  << mFormatNumChkBx
381  << mFormatNumDDBtn
382  << mFormatNumDecimalsDDBtn
383  << mFormatNumDecimalsSpnBx
384  << mFormatNumPlusSignChkBx
385  << mFormatNumPlusSignDDBtn
386  << mIsObstacleDDBtn
387  << mLimitLabelChkBox
388  << mLimitLabelSpinBox
389  << mLineDistanceDDBtn
390  << mLineDistanceSpnBx
391  << mLineDistanceUnitDDBtn
392  << mLineDistanceUnitWidget
393  << mMaxCharAngleDDBtn
394  << mMaxCharAngleInDSpinBox
395  << mMaxCharAngleOutDSpinBox
396  << mMinSizeSpinBox
397  << mObstacleFactorDDBtn
398  << mObstacleFactorSlider
399  << mObstacleTypeComboBox
400  << mOffsetTypeComboBox
401  << mPalShowAllLabelsForLayerChkBx
402  << mPointAngleSpinBox
403  << mPointOffsetDDBtn
404  << mPointOffsetUnitsDDBtn
405  << mPointOffsetUnitWidget
406  << mPointOffsetXSpinBox
407  << mPointOffsetYSpinBox
408  << mPointPositionOrderDDBtn
409  << mPointQuadOffsetDDBtn
410  << mPreviewBackgroundBtn
411  << mPreviewTextEdit
412  << mPriorityDDBtn
413  << mPrioritySlider
414  << mRepeatDistanceDDBtn
415  << mRepeatDistanceSpinBox
416  << mRepeatDistanceUnitDDBtn
417  << mRepeatDistanceUnitWidget
418  << mScaleBasedVisibilityChkBx
419  << mScaleBasedVisibilityDDBtn
420  << mScaleBasedVisibilityMaxDDBtn
421  << mMaxScaleWidget
422  << mScaleBasedVisibilityMinDDBtn
423  << mMinScaleWidget
424  << mShadowBlendCmbBx
425  << mShadowBlendDDBtn
426  << mShadowColorBtn
427  << mShadowColorDDBtn
428  << mShadowDrawChkBx
429  << mShadowDrawDDBtn
430  << mShadowOffsetAngleDDBtn
431  << mShadowOffsetAngleSpnBx
432  << mShadowOffsetDDBtn
433  << mShadowOffsetGlobalChkBx
434  << mShadowOffsetSpnBx
435  << mShadowOffsetUnitsDDBtn
436  << mShadowOffsetUnitWidget
437  << mShadowRadiusAlphaChkBx
438  << mShadowRadiusDDBtn
439  << mShadowRadiusDblSpnBx
440  << mShadowRadiusUnitsDDBtn
441  << mShadowRadiusUnitWidget
442  << mShadowScaleDDBtn
443  << mShadowScaleSpnBx
444  << mShadowOpacityDDBtn
445  << mShadowOpacityWidget
446  << mShadowUnderCmbBx
447  << mShadowUnderDDBtn
448  << mShapeBlendCmbBx
449  << mShapeBlendModeDDBtn
450  << mShapeStrokeColorBtn
451  << mShapeStrokeColorDDBtn
452  << mShapeStrokeUnitsDDBtn
453  << mShapeStrokeWidthDDBtn
454  << mShapeStrokeWidthSpnBx
455  << mShapeStrokeWidthUnitWidget
456  << mShapeDrawChkBx
457  << mShapeDrawDDBtn
458  << mShapeFillColorBtn
459  << mShapeFillColorDDBtn
460  << mShapeOffsetDDBtn
461  << mShapeOffsetUnitsDDBtn
462  << mShapeOffsetXSpnBx
463  << mShapeOffsetYSpnBx
464  << mShapeOffsetUnitWidget
465  << mShapePenStyleCmbBx
466  << mShapePenStyleDDBtn
467  << mShapeRadiusDDBtn
468  << mShapeRadiusUnitsDDBtn
469  << mShapeRadiusXDbSpnBx
470  << mShapeRadiusYDbSpnBx
471  << mShapeRotationCmbBx
472  << mShapeRotationDDBtn
473  << mShapeRotationDblSpnBx
474  << mShapeRotationTypeDDBtn
475  << mShapeRadiusUnitWidget
476  << mShapeSVGPathDDBtn
477  << mShapeSVGPathLineEdit
478  << mShapeSizeCmbBx
479  << mShapeSizeTypeDDBtn
480  << mShapeSizeUnitsDDBtn
481  << mShapeSizeUnitWidget
482  << mShapeSizeXDDBtn
483  << mShapeSizeXSpnBx
484  << mShapeSizeYDDBtn
485  << mShapeSizeYSpnBx
486  << mShapeOpacityDDBtn
487  << mBackgroundOpacityWidget
488  << mShapeTypeCmbBx
489  << mShapeTypeDDBtn
490  << mShowLabelDDBtn
491  << mWrapCharDDBtn
492  << mAutoWrapLengthDDBtn
493  << mZIndexDDBtn
494  << mZIndexSpinBox
495  << spinBufferSize
496  << wrapCharacterEdit
497  << mAutoWrapLengthSpinBox
498  << mAutoWrapTypeComboBox
499  << mCentroidRadioVisible
500  << mCentroidRadioWhole
501  << mDirectSymbRadioBtnAbove
502  << mDirectSymbRadioBtnBelow
503  << mDirectSymbRadioBtnLR
504  << mUpsidedownRadioAll
505  << mUpsidedownRadioDefined
506  << mUpsidedownRadioOff
507  << radAroundCentroid
508  << radAroundPoint
509  << radLineCurved
510  << radLineHorizontal
511  << radLineParallel
512  << radOverCentroid
513  << radOverPoint
514  << radPolygonFree
515  << radPolygonHorizontal
516  << radPolygonPerimeter
517  << radPolygonPerimeterCurved
518  << radPredefinedOrder
519  << mFieldExpressionWidget
520  << mCheckBoxSubstituteText;
521  connectValueChanged( widgets, SLOT( updatePreview() ) );
522 
523  connect( mQuadrantBtnGrp, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ), this, &QgsTextFormatWidget::updatePreview );
524 
525  // set correct initial tab to match displayed setting page
526  whileBlocking( mOptionsTab )->setCurrentIndex( mLabelStackedWidget->currentIndex() );
527 
528  if ( mMapCanvas )
529  {
530  lblFontPreview->setMapUnits( mMapCanvas->mapSettings().mapUnits() );
531  mPreviewScaleComboBox->setScale( mMapCanvas->mapSettings().scale() );
532  }
533 }
534 
535 void QgsTextFormatWidget::setWidgetMode( QgsTextFormatWidget::Mode mode )
536 {
537  mWidgetMode = mode;
538  switch ( mode )
539  {
540  case Labeling:
541  toggleDDButtons( true );
542  break;
543 
544  case Text:
545  toggleDDButtons( false );
546  delete mLabelingOptionsListWidget->takeItem( 6 );
547  delete mLabelingOptionsListWidget->takeItem( 5 );
548  mOptionsTab->removeTab( 6 );
549  mOptionsTab->removeTab( 5 );
550 
551  frameLabelWith->hide();
552  mDirectSymbolsFrame->hide();
553  mFormatNumFrame->hide();
554  mFormatNumChkBx->hide();
555  mFormatNumDDBtn->hide();
556  mSubstitutionsFrame->hide();
557  mFontBoldBtn->hide();
558  mFontItalicBtn->hide();
559 
560  break;
561  }
562 }
563 
564 void QgsTextFormatWidget::toggleDDButtons( bool visible )
565 {
566  Q_FOREACH ( QgsPropertyOverrideButton *button, findChildren< QgsPropertyOverrideButton * >() )
567  {
568  button->setVisible( visible );
569  }
570 }
571 
573 {
574  mOptionsTab->setVisible( enabled );
575  mOptionsTab->setTabToolTip( 0, tr( "Text" ) );
576  mOptionsTab->setTabToolTip( 1, tr( "Formatting" ) );
577  mOptionsTab->setTabToolTip( 2, tr( "Buffer" ) );
578  mOptionsTab->setTabToolTip( 3, tr( "Background" ) );
579  mOptionsTab->setTabToolTip( 4, tr( "Shadow" ) );
580  mOptionsTab->setTabToolTip( 5, tr( "Placement" ) );
581  mOptionsTab->setTabToolTip( 6, tr( "Rendering" ) );
582 
583  mLabelingOptionsListFrame->setVisible( !enabled );
584  groupBox_mPreview->setVisible( !enabled );
585  mDockMode = enabled;
586 }
587 
588 void QgsTextFormatWidget::connectValueChanged( const QList<QWidget *> &widgets, const char *slot )
589 {
590  Q_FOREACH ( QWidget *widget, widgets )
591  {
592  if ( QgsPropertyOverrideButton *w = qobject_cast<QgsPropertyOverrideButton *>( widget ) )
593  {
594  connect( w, SIGNAL( changed() ), this, slot );
595  }
596  else if ( QgsFieldExpressionWidget *w = qobject_cast< QgsFieldExpressionWidget *>( widget ) )
597  {
598  connect( w, SIGNAL( fieldChanged( QString ) ), this, slot );
599  }
600  else if ( QgsOpacityWidget *w = qobject_cast< QgsOpacityWidget *>( widget ) )
601  {
602  connect( w, SIGNAL( opacityChanged( double ) ), this, slot );
603  }
604  else if ( QgsScaleWidget *w = qobject_cast< QgsScaleWidget *>( widget ) )
605  {
606  connect( w, SIGNAL( scaleChanged( double ) ), this, slot );
607  }
608  else if ( QgsUnitSelectionWidget *w = qobject_cast<QgsUnitSelectionWidget *>( widget ) )
609  {
610  connect( w, SIGNAL( changed() ), this, slot );
611  }
612  else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
613  {
614  connect( w, SIGNAL( currentIndexChanged( int ) ), this, slot );
615  }
616  else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
617  {
618  connect( w, SIGNAL( valueChanged( int ) ), this, slot );
619  }
620  else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
621  {
622  connect( w, SIGNAL( valueChanged( double ) ), this, slot );
623  }
624  else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
625  {
626  connect( w, SIGNAL( colorChanged( QColor ) ), this, slot );
627  }
628  else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
629  {
630  connect( w, SIGNAL( toggled( bool ) ), this, slot );
631  }
632  else if ( QRadioButton *w = qobject_cast<QRadioButton *>( widget ) )
633  {
634  connect( w, SIGNAL( toggled( bool ) ), this, slot );
635  }
636  else if ( QLineEdit *w = qobject_cast<QLineEdit *>( widget ) )
637  {
638  connect( w, SIGNAL( textEdited( QString ) ), this, slot );
639  }
640  else if ( QSlider *w = qobject_cast<QSlider *>( widget ) )
641  {
642  connect( w, SIGNAL( valueChanged( int ) ), this, slot );
643  }
644  else
645  {
646  QgsLogger::warning( QStringLiteral( "Could not create connection for widget %1" ).arg( widget->objectName() ) );
647  }
648  }
649 }
650 
652 {
653  QgsTextBufferSettings buffer = format.buffer();
654  QgsTextBackgroundSettings background = format.background();
655  QgsTextShadowSettings shadow = format.shadow();
656 
657  // buffer
658  mBufferDrawChkBx->setChecked( buffer.enabled() );
659  spinBufferSize->setValue( buffer.size() );
660  mBufferUnitWidget->setUnit( buffer.sizeUnit() );
661  mBufferUnitWidget->setMapUnitScale( buffer.sizeMapUnitScale() );
662  btnBufferColor->setColor( buffer.color() );
663  mBufferOpacityWidget->setOpacity( buffer.opacity() );
664  mBufferJoinStyleComboBox->setPenJoinStyle( buffer.joinStyle() );
665  mBufferTranspFillChbx->setChecked( buffer.fillBufferInterior() );
666  comboBufferBlendMode->setBlendMode( buffer.blendMode() );
667  if ( buffer.paintEffect() )
668  mBufferEffect.reset( buffer.paintEffect()->clone() );
669  else
670  {
671  mBufferEffect.reset( QgsPaintEffectRegistry::defaultStack() );
672  mBufferEffect->setEnabled( false );
673  }
674  mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );
675 
676  mFontSizeUnitWidget->setUnit( format.sizeUnit() );
677  mFontSizeUnitWidget->setMapUnitScale( format.sizeMapUnitScale() );
678  mRefFont = format.font();
679  mFontSizeSpinBox->setValue( format.size() );
680  btnTextColor->setColor( format.color() );
681  mTextOpacityWidget->setOpacity( format.opacity() );
682  comboBlendMode->setBlendMode( format.blendMode() );
683 
684  mFontWordSpacingSpinBox->setValue( format.font().wordSpacing() );
685  mFontLetterSpacingSpinBox->setValue( format.font().letterSpacing() );
686 
687  QgsFontUtils::updateFontViaStyle( mRefFont, format.namedStyle() );
688  updateFont( mRefFont );
689 
690  // show 'font not found' if substitution has occurred (should come after updateFont())
691  mFontMissingLabel->setVisible( !format.fontFound() );
692  if ( !format.fontFound() )
693  {
694  QString missingTxt = tr( "%1 not found. Default substituted." );
695  QString txtPrepend = tr( "Chosen font" );
696  if ( !format.resolvedFontFamily().isEmpty() )
697  {
698  txtPrepend = QStringLiteral( "'%1'" ).arg( format.resolvedFontFamily() );
699  }
700  mFontMissingLabel->setText( missingTxt.arg( txtPrepend ) );
701 
702  // ensure user is sent to 'Text style' section to see notice
703  mLabelingOptionsListWidget->setCurrentRow( 0 );
704  }
705  mFontLineHeightSpinBox->setValue( format.lineHeight() );
706 
707  // shape background
708  mShapeDrawChkBx->setChecked( background.enabled() );
709  mShapeTypeCmbBx->blockSignals( true );
710  mShapeTypeCmbBx->setCurrentIndex( background.type() );
711  mShapeTypeCmbBx->blockSignals( false );
712  mShapeSVGPathLineEdit->setText( background.svgFile() );
713 
714  mShapeSizeCmbBx->setCurrentIndex( background.sizeType() );
715  mShapeSizeXSpnBx->setValue( background.size().width() );
716  mShapeSizeYSpnBx->setValue( background.size().height() );
717  mShapeSizeUnitWidget->setUnit( background.sizeUnit() );
718  mShapeSizeUnitWidget->setMapUnitScale( background.sizeMapUnitScale() );
719  mShapeRotationCmbBx->setCurrentIndex( background.rotationType() );
720  mShapeRotationDblSpnBx->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync );
721  mShapeRotationDDBtn->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync );
722  mShapeRotationDblSpnBx->setValue( background.rotation() );
723  mShapeOffsetXSpnBx->setValue( background.offset().x() );
724  mShapeOffsetYSpnBx->setValue( background.offset().y() );
725  mShapeOffsetUnitWidget->setUnit( background.offsetUnit() );
726  mShapeOffsetUnitWidget->setMapUnitScale( background.offsetMapUnitScale() );
727  mShapeRadiusXDbSpnBx->setValue( background.radii().width() );
728  mShapeRadiusYDbSpnBx->setValue( background.radii().height() );
729  mShapeRadiusUnitWidget->setUnit( background.radiiUnit() );
730  mShapeRadiusUnitWidget->setMapUnitScale( background.radiiMapUnitScale() );
731 
732  mShapeFillColorBtn->setColor( background.fillColor() );
733  mShapeStrokeColorBtn->setColor( background.strokeColor() );
734  mShapeStrokeWidthSpnBx->setValue( background.strokeWidth() );
735  mShapeStrokeWidthUnitWidget->setUnit( background.strokeWidthUnit() );
736  mShapeStrokeWidthUnitWidget->setMapUnitScale( background.strokeWidthMapUnitScale() );
737  mShapePenStyleCmbBx->setPenJoinStyle( background.joinStyle() );
738 
739  mBackgroundOpacityWidget->setOpacity( background.opacity() );
740  mShapeBlendCmbBx->setBlendMode( background.blendMode() );
741 
742  mLoadSvgParams = false;
743  mShapeTypeCmbBx_currentIndexChanged( background.type() ); // force update of shape background gui
744 
745  if ( background.paintEffect() )
746  mBackgroundEffect.reset( background.paintEffect()->clone() );
747  else
748  {
749  mBackgroundEffect.reset( QgsPaintEffectRegistry::defaultStack() );
750  mBackgroundEffect->setEnabled( false );
751  }
752  mBackgroundEffectWidget->setPaintEffect( mBackgroundEffect.get() );
753 
754  // drop shadow
755  mShadowDrawChkBx->setChecked( shadow.enabled() );
756  mShadowUnderCmbBx->setCurrentIndex( shadow.shadowPlacement() );
757  mShadowOffsetAngleSpnBx->setValue( shadow.offsetAngle() );
758  mShadowOffsetSpnBx->setValue( shadow.offsetDistance() );
759  mShadowOffsetUnitWidget->setUnit( shadow.offsetUnit() );
760  mShadowOffsetUnitWidget->setMapUnitScale( shadow.offsetMapUnitScale() );
761  mShadowOffsetGlobalChkBx->setChecked( shadow.offsetGlobal() );
762 
763  mShadowRadiusDblSpnBx->setValue( shadow.blurRadius() );
764  mShadowRadiusUnitWidget->setUnit( shadow.blurRadiusUnit() );
765  mShadowRadiusUnitWidget->setMapUnitScale( shadow.blurRadiusMapUnitScale() );
766  mShadowRadiusAlphaChkBx->setChecked( shadow.blurAlphaOnly() );
767  mShadowOpacityWidget->setOpacity( shadow.opacity() );
768  mShadowScaleSpnBx->setValue( shadow.scale() );
769 
770  mShadowColorBtn->setColor( shadow.color() );
771  mShadowBlendCmbBx->setBlendMode( shadow.blendMode() );
772 
773 }
774 
776 {
777  QgsSettings settings;
778  settings.setValue( QStringLiteral( "Windows/Labeling/FontPreviewSplitState" ), mFontPreviewSplitter->saveState() );
779  settings.setValue( QStringLiteral( "Windows/Labeling/OptionsSplitState" ), mLabelingOptionsSplitter->saveState() );
780  settings.setValue( QStringLiteral( "Windows/Labeling/Tab" ), mLabelingOptionsListWidget->currentRow() );
781 }
782 
784 {
786  format.setColor( btnTextColor->color() );
787  format.setFont( mRefFont );
788  format.setSize( mFontSizeSpinBox->value() );
789  format.setNamedStyle( mFontStyleComboBox->currentText() );
790  format.setOpacity( mTextOpacityWidget->opacity() );
791  format.setBlendMode( comboBlendMode->blendMode() );
792  format.setSizeUnit( mFontSizeUnitWidget->unit() );
793  format.setSizeMapUnitScale( mFontSizeUnitWidget->getMapUnitScale() );
794  format.setLineHeight( mFontLineHeightSpinBox->value() );
795 
796  // buffer
797  QgsTextBufferSettings buffer;
798  buffer.setEnabled( mBufferDrawChkBx->isChecked() );
799  buffer.setSize( spinBufferSize->value() );
800  buffer.setColor( btnBufferColor->color() );
801  buffer.setOpacity( mBufferOpacityWidget->opacity() );
802  buffer.setSizeUnit( mBufferUnitWidget->unit() );
803  buffer.setSizeMapUnitScale( mBufferUnitWidget->getMapUnitScale() );
804  buffer.setJoinStyle( mBufferJoinStyleComboBox->penJoinStyle() );
805  buffer.setFillBufferInterior( mBufferTranspFillChbx->isChecked() );
806  buffer.setBlendMode( comboBufferBlendMode->blendMode() );
807  if ( mBufferEffect && !QgsPaintEffectRegistry::isDefaultStack( mBufferEffect.get() ) )
808  buffer.setPaintEffect( mBufferEffect->clone() );
809  else
810  buffer.setPaintEffect( nullptr );
811  format.setBuffer( buffer );
812 
813  // shape background
814  QgsTextBackgroundSettings background;
815  background.setEnabled( mShapeDrawChkBx->isChecked() );
816  background.setType( ( QgsTextBackgroundSettings::ShapeType )mShapeTypeCmbBx->currentIndex() );
817  background.setSvgFile( mShapeSVGPathLineEdit->text() );
818  background.setSizeType( ( QgsTextBackgroundSettings::SizeType )mShapeSizeCmbBx->currentIndex() );
819  background.setSize( QSizeF( mShapeSizeXSpnBx->value(), mShapeSizeYSpnBx->value() ) );
820  background.setSizeUnit( mShapeSizeUnitWidget->unit() );
821  background.setSizeMapUnitScale( mShapeSizeUnitWidget->getMapUnitScale() );
822  background.setRotationType( ( QgsTextBackgroundSettings::RotationType )( mShapeRotationCmbBx->currentIndex() ) );
823  background.setRotation( mShapeRotationDblSpnBx->value() );
824  background.setOffset( QPointF( mShapeOffsetXSpnBx->value(), mShapeOffsetYSpnBx->value() ) );
825  background.setOffsetUnit( mShapeOffsetUnitWidget->unit() );
826  background.setOffsetMapUnitScale( mShapeOffsetUnitWidget->getMapUnitScale() );
827  background.setRadii( QSizeF( mShapeRadiusXDbSpnBx->value(), mShapeRadiusYDbSpnBx->value() ) );
828  background.setRadiiUnit( mShapeRadiusUnitWidget->unit() );
829  background.setRadiiMapUnitScale( mShapeRadiusUnitWidget->getMapUnitScale() );
830 
831  background.setFillColor( mShapeFillColorBtn->color() );
832  background.setStrokeColor( mShapeStrokeColorBtn->color() );
833  background.setStrokeWidth( mShapeStrokeWidthSpnBx->value() );
834  background.setStrokeWidthUnit( mShapeStrokeWidthUnitWidget->unit() );
835  background.setStrokeWidthMapUnitScale( mShapeStrokeWidthUnitWidget->getMapUnitScale() );
836  background.setJoinStyle( mShapePenStyleCmbBx->penJoinStyle() );
837  background.setOpacity( mBackgroundOpacityWidget->opacity() );
838  background.setBlendMode( mShapeBlendCmbBx->blendMode() );
839  if ( mBackgroundEffect && !QgsPaintEffectRegistry::isDefaultStack( mBackgroundEffect.get() ) )
840  background.setPaintEffect( mBackgroundEffect->clone() );
841  else
842  background.setPaintEffect( nullptr );
843  format.setBackground( background );
844 
845  // drop shadow
846  QgsTextShadowSettings shadow;
847  shadow.setEnabled( mShadowDrawChkBx->isChecked() );
848  shadow.setShadowPlacement( ( QgsTextShadowSettings::ShadowPlacement )mShadowUnderCmbBx->currentIndex() );
849  shadow.setOffsetAngle( mShadowOffsetAngleSpnBx->value() );
850  shadow.setOffsetDistance( mShadowOffsetSpnBx->value() );
851  shadow.setOffsetUnit( mShadowOffsetUnitWidget->unit() );
852  shadow.setOffsetMapUnitScale( mShadowOffsetUnitWidget->getMapUnitScale() );
853  shadow.setOffsetGlobal( mShadowOffsetGlobalChkBx->isChecked() );
854  shadow.setBlurRadius( mShadowRadiusDblSpnBx->value() );
855  shadow.setBlurRadiusUnit( mShadowRadiusUnitWidget->unit() );
856  shadow.setBlurRadiusMapUnitScale( mShadowRadiusUnitWidget->getMapUnitScale() );
857  shadow.setBlurAlphaOnly( mShadowRadiusAlphaChkBx->isChecked() );
858  shadow.setOpacity( mShadowOpacityWidget->opacity() );
859  shadow.setScale( mShadowScaleSpnBx->value() );
860  shadow.setColor( mShadowColorBtn->color() );
861  shadow.setBlendMode( mShadowBlendCmbBx->blendMode() );
862  format.setShadow( shadow );
863 
864  return format;
865 }
866 
868 {
869  updateWidgetForFormat( format );
870 }
871 
872 void QgsTextFormatWidget::optionsStackedWidget_CurrentChanged( int indx )
873 {
874  mLabelingOptionsListWidget->blockSignals( true );
875  mLabelingOptionsListWidget->setCurrentRow( indx );
876  mLabelingOptionsListWidget->blockSignals( false );
877 }
878 
879 void QgsTextFormatWidget::collapseSample( bool collapse )
880 {
881  if ( collapse )
882  {
883  QList<int> splitSizes = mFontPreviewSplitter->sizes();
884  if ( splitSizes[0] > groupBox_mPreview->height() )
885  {
886  int delta = splitSizes[0] - groupBox_mPreview->height();
887  splitSizes[0] -= delta;
888  splitSizes[1] += delta;
889  mFontPreviewSplitter->setSizes( splitSizes );
890  }
891  }
892 }
893 
894 void QgsTextFormatWidget::changeTextColor( const QColor &color )
895 {
896  Q_UNUSED( color )
897  updatePreview();
898 }
899 
900 void QgsTextFormatWidget::updateFont( const QFont &font )
901 {
902  // update background reference font
903  if ( font != mRefFont )
904  {
905  mRefFont = font;
906  }
907 
908  // test if font is actually available
909  // NOTE: QgsFontUtils::fontMatchOnSystem may fail here, just crosscheck family
910  mFontMissingLabel->setVisible( !QgsFontUtils::fontFamilyMatchOnSystem( mRefFont.family() ) );
911 
912  mDirectSymbLeftLineEdit->setFont( mRefFont );
913  mDirectSymbRightLineEdit->setFont( mRefFont );
914 
915  blockFontChangeSignals( true );
916  mFontFamilyCmbBx->setCurrentFont( mRefFont );
917  populateFontStyleComboBox();
918  int idx = mFontCapitalsComboBox->findData( QVariant( ( unsigned int ) mRefFont.capitalization() ) );
919  mFontCapitalsComboBox->setCurrentIndex( idx == -1 ? 0 : idx );
920  mFontUnderlineBtn->setChecked( mRefFont.underline() );
921  mFontStrikethroughBtn->setChecked( mRefFont.strikeOut() );
922  blockFontChangeSignals( false );
923 
924  // update font name with font face
925 // font.setPixelSize( 24 );
926 
927  updatePreview();
928 }
929 
930 void QgsTextFormatWidget::blockFontChangeSignals( bool blk )
931 {
932  mFontFamilyCmbBx->blockSignals( blk );
933  mFontStyleComboBox->blockSignals( blk );
934  mFontCapitalsComboBox->blockSignals( blk );
935  mFontUnderlineBtn->blockSignals( blk );
936  mFontStrikethroughBtn->blockSignals( blk );
937  mFontWordSpacingSpinBox->blockSignals( blk );
938  mFontLetterSpacingSpinBox->blockSignals( blk );
939 }
940 
941 void QgsTextFormatWidget::updatePreview()
942 {
943  // In dock mode we don't have a preview we
944  // just let stuff know we have changed because
945  // there might be live updates connected.
946  if ( mDockMode )
947  {
948  emit widgetChanged();
949  return;
950  }
951 
952  scrollPreview();
953  lblFontPreview->setFormat( format() );
954 }
955 
956 void QgsTextFormatWidget::scrollPreview()
957 {
958  scrollArea_mPreview->ensureVisible( 0, 0, 0, 0 );
959 }
960 
961 void QgsTextFormatWidget::setPreviewBackground( const QColor &color )
962 {
963  scrollArea_mPreview->widget()->setStyleSheet( QStringLiteral( "background: rgb(%1, %2, %3);" ).arg( QString::number( color.red() ),
964  QString::number( color.green() ),
965  QString::number( color.blue() ) ) );
966 }
967 
968 void QgsTextFormatWidget::changeBufferColor( const QColor &color )
969 {
970  Q_UNUSED( color )
971  updatePreview();
972 }
973 
975 {
976  QWidget *curWdgt = stackedPlacement->currentWidget();
977 
978  bool showLineFrame = false;
979  bool showCentroidFrame = false;
980  bool showQuadrantFrame = false;
981  bool showFixedQuadrantFrame = false;
982  bool showPlacementPriorityFrame = false;
983  bool showOffsetTypeFrame = false;
984  bool showOffsetFrame = false;
985  bool showDistanceFrame = false;
986  bool showRotationFrame = false;
987  bool showMaxCharAngleFrame = false;
988 
989  bool enableMultiLinesFrame = true;
990 
991  if ( ( curWdgt == pagePoint && radAroundPoint->isChecked() )
992  || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
993  {
994  showCentroidFrame = ( curWdgt == pagePolygon && radAroundCentroid->isChecked() );
995  showDistanceFrame = true;
996  //showRotationFrame = true; // TODO: uncomment when supported
997  if ( curWdgt == pagePoint )
998  {
999  showQuadrantFrame = true;
1000  }
1001  }
1002  else if ( ( curWdgt == pagePoint && radOverPoint->isChecked() )
1003  || ( curWdgt == pagePolygon && radOverCentroid->isChecked() ) )
1004  {
1005  showCentroidFrame = ( curWdgt == pagePolygon && radOverCentroid->isChecked() );
1006  showQuadrantFrame = true;
1007  showFixedQuadrantFrame = true;
1008  showOffsetFrame = true;
1009  showRotationFrame = true;
1010  }
1011  else if ( curWdgt == pagePoint && radPredefinedOrder->isChecked() )
1012  {
1013  showDistanceFrame = true;
1014  showPlacementPriorityFrame = true;
1015  showOffsetTypeFrame = true;
1016  }
1017  else if ( ( curWdgt == pageLine && radLineParallel->isChecked() )
1018  || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() )
1019  || ( curWdgt == pageLine && radLineCurved->isChecked() )
1020  || ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() ) )
1021  {
1022  showLineFrame = true;
1023  showDistanceFrame = true;
1024  //showRotationFrame = true; // TODO: uncomment when supported
1025 
1026  bool offline = chkLineAbove->isChecked() || chkLineBelow->isChecked();
1027  chkLineOrientationDependent->setEnabled( offline );
1028  mPlacementDistanceFrame->setEnabled( offline );
1029 
1030  bool isCurved = ( curWdgt == pageLine && radLineCurved->isChecked() )
1031  || ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() );
1032  showMaxCharAngleFrame = isCurved;
1033  // TODO: enable mMultiLinesFrame when supported for curved labels
1034  enableMultiLinesFrame = !isCurved;
1035  }
1036 
1037  mPlacementLineFrame->setVisible( showLineFrame );
1038  mPlacementCentroidFrame->setVisible( showCentroidFrame );
1039  mPlacementQuadrantFrame->setVisible( showQuadrantFrame );
1040  mPlacementFixedQuadrantFrame->setVisible( showFixedQuadrantFrame );
1041  mPlacementCartographicFrame->setVisible( showPlacementPriorityFrame );
1042  mPlacementOffsetFrame->setVisible( showOffsetFrame );
1043  mPlacementDistanceFrame->setVisible( showDistanceFrame );
1044  mPlacementOffsetTypeFrame->setVisible( showOffsetTypeFrame );
1045  mPlacementRotationFrame->setVisible( showRotationFrame );
1046  mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon &&
1047  ( radPolygonPerimeter->isChecked() || radPolygonPerimeterCurved->isChecked() ) ) );
1048  mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame );
1049 
1050  mMultiLinesFrame->setEnabled( enableMultiLinesFrame );
1051 }
1052 
1053 void QgsTextFormatWidget::populateFontCapitalsComboBox()
1054 {
1055  mFontCapitalsComboBox->addItem( tr( "No change" ), QVariant( 0 ) );
1056  mFontCapitalsComboBox->addItem( tr( "All uppercase" ), QVariant( 1 ) );
1057  mFontCapitalsComboBox->addItem( tr( "All lowercase" ), QVariant( 2 ) );
1058  // Small caps doesn't work right with QPainterPath::addText()
1059  // https://bugreports.qt.io/browse/QTBUG-13965
1060 // mFontCapitalsComboBox->addItem( tr( "Small caps" ), QVariant( 3 ) );
1061  mFontCapitalsComboBox->addItem( tr( "Capitalize first letter" ), QVariant( 4 ) );
1062 }
1063 
1064 void QgsTextFormatWidget::populateFontStyleComboBox()
1065 {
1066  mFontStyleComboBox->clear();
1067  QStringList styles = mFontDB.styles( mRefFont.family() );
1068  Q_FOREACH ( const QString &style, styles )
1069  {
1070  mFontStyleComboBox->addItem( style );
1071  }
1072 
1073  QString targetStyle = mFontDB.styleString( mRefFont );
1074  if ( !styles.contains( targetStyle ) )
1075  {
1076  QFont f = QFont( mRefFont.family() );
1077  targetStyle = QFontInfo( f ).styleName();
1078  mRefFont.setStyleName( targetStyle );
1079  }
1080  int curIndx = 0;
1081  int stylIndx = mFontStyleComboBox->findText( targetStyle );
1082  if ( stylIndx > -1 )
1083  {
1084  curIndx = stylIndx;
1085  }
1086 
1087  mFontStyleComboBox->setCurrentIndex( curIndx );
1088 }
1089 
1090 void QgsTextFormatWidget::mFontSizeSpinBox_valueChanged( double d )
1091 {
1092  mRefFont.setPointSizeF( d );
1093  updateFont( mRefFont );
1094 }
1095 
1096 void QgsTextFormatWidget::mFontCapitalsComboBox_currentIndexChanged( int index )
1097 {
1098  int capitalsindex = mFontCapitalsComboBox->itemData( index ).toUInt();
1099  mRefFont.setCapitalization( ( QFont::Capitalization ) capitalsindex );
1100  updateFont( mRefFont );
1101 }
1102 
1103 void QgsTextFormatWidget::mFontFamilyCmbBx_currentFontChanged( const QFont &f )
1104 {
1105  mRefFont.setFamily( f.family() );
1106  updateFont( mRefFont );
1107 }
1108 
1109 void QgsTextFormatWidget::mFontStyleComboBox_currentIndexChanged( const QString &text )
1110 {
1111  QgsFontUtils::updateFontViaStyle( mRefFont, text );
1112  updateFont( mRefFont );
1113 }
1114 
1115 void QgsTextFormatWidget::mFontUnderlineBtn_toggled( bool ckd )
1116 {
1117  mRefFont.setUnderline( ckd );
1118  updateFont( mRefFont );
1119 }
1120 
1121 void QgsTextFormatWidget::mFontStrikethroughBtn_toggled( bool ckd )
1122 {
1123  mRefFont.setStrikeOut( ckd );
1124  updateFont( mRefFont );
1125 }
1126 
1127 void QgsTextFormatWidget::mFontWordSpacingSpinBox_valueChanged( double spacing )
1128 {
1129  mRefFont.setWordSpacing( spacing );
1130  updateFont( mRefFont );
1131 }
1132 
1133 void QgsTextFormatWidget::mFontLetterSpacingSpinBox_valueChanged( double spacing )
1134 {
1135  mRefFont.setLetterSpacing( QFont::AbsoluteSpacing, spacing );
1136  updateFont( mRefFont );
1137 }
1138 
1139 void QgsTextFormatWidget::mFontSizeUnitWidget_changed()
1140 {
1141  // disable pixel size limiting for labels defined in points
1142  if ( mFontSizeUnitWidget->unit() != QgsUnitTypes::RenderMapUnits )
1143  {
1144  mFontLimitPixelChkBox->setChecked( false );
1145  }
1146  else if ( mMinPixelLimit == 0 )
1147  {
1148  // initial minimum trigger value set, turn on pixel size limiting by default
1149  // for labels defined in map units (ignored after first settings save)
1150  mFontLimitPixelChkBox->setChecked( true );
1151  }
1152  updateFont( mRefFont );
1153 }
1154 
1155 void QgsTextFormatWidget::mFontMinPixelSpinBox_valueChanged( int px )
1156 {
1157  // ensure max font pixel size for map unit labels can't be lower than min
1158  mFontMaxPixelSpinBox->setMinimum( px );
1159  mFontMaxPixelSpinBox->update();
1160 }
1161 
1162 void QgsTextFormatWidget::mFontMaxPixelSpinBox_valueChanged( int px )
1163 {
1164  // ensure max font pixel size for map unit labels can't be lower than min
1165  if ( px < mFontMinPixelSpinBox->value() )
1166  {
1167  mFontMaxPixelSpinBox->blockSignals( true );
1168  mFontMaxPixelSpinBox->setValue( mFontMinPixelSpinBox->value() );
1169  mFontMaxPixelSpinBox->blockSignals( false );
1170  }
1171  mFontMaxPixelSpinBox->setMinimum( mFontMinPixelSpinBox->value() );
1172 }
1173 
1174 void QgsTextFormatWidget::mBufferUnitWidget_changed()
1175 {
1176  updateFont( mRefFont );
1177 }
1178 
1179 void QgsTextFormatWidget::mCoordXDDBtn_activated( bool active )
1180 {
1181  if ( !active ) //no data defined alignment without data defined position
1182  {
1183  enableDataDefinedAlignment( false );
1184  }
1185  else if ( mCoordYDDBtn->isActive() )
1186  {
1188  }
1189 }
1190 
1191 void QgsTextFormatWidget::mCoordYDDBtn_activated( bool active )
1192 {
1193  if ( !active ) //no data defined alignment without data defined position
1194  {
1195  enableDataDefinedAlignment( false );
1196  }
1197  else if ( mCoordXDDBtn->isActive() )
1198  {
1200  }
1201 }
1202 
1203 void QgsTextFormatWidget::mShapeTypeCmbBx_currentIndexChanged( int index )
1204 {
1205  // shape background
1209 
1210  showBackgroundPenStyle( isRect );
1211  showBackgroundRadius( isRect );
1212 
1213  mShapeSVGPathFrame->setVisible( isSVG );
1214  // symbology SVG renderer only supports size^2 scaling, so we only use the x size spinbox
1215  mShapeSizeYLabel->setVisible( !isSVG );
1216  mShapeSizeYSpnBx->setVisible( !isSVG );
1217  mShapeSizeYDDBtn->setVisible( !isSVG && mWidgetMode == Labeling );
1218  mShapeSizeXLabel->setText( tr( "Size%1" ).arg( !isSVG ? tr( " X" ) : QString() ) );
1219 
1220  // SVG parameter setting doesn't support color's alpha component yet
1221  mShapeFillColorBtn->setAllowOpacity( !isSVG );
1222  mShapeFillColorBtn->setButtonBackground();
1223  mShapeStrokeColorBtn->setAllowOpacity( !isSVG );
1224  mShapeStrokeColorBtn->setButtonBackground();
1225 
1226  // configure SVG parameter widgets
1227  mShapeSVGParamsBtn->setVisible( isSVG );
1228  if ( isSVG )
1229  {
1230  updateSvgWidgets( mShapeSVGPathLineEdit->text() );
1231  }
1232  else
1233  {
1234  mShapeFillColorLabel->setEnabled( true );
1235  mShapeFillColorBtn->setEnabled( true );
1236  mShapeFillColorDDBtn->setEnabled( true );
1237  mShapeStrokeColorLabel->setEnabled( true );
1238  mShapeStrokeColorBtn->setEnabled( true );
1239  mShapeStrokeColorDDBtn->setEnabled( true );
1240  mShapeStrokeWidthLabel->setEnabled( true );
1241  mShapeStrokeWidthSpnBx->setEnabled( true );
1242  mShapeStrokeWidthDDBtn->setEnabled( true );
1243  }
1244  // TODO: fix overriding SVG symbol's stroke width units in QgsSvgCache
1245  // currently broken, fall back to symbol units only
1246  mShapeStrokeWidthUnitWidget->setVisible( !isSVG );
1247  mShapeSVGUnitsLabel->setVisible( isSVG );
1248  mShapeStrokeUnitsDDBtn->setEnabled( !isSVG );
1249 }
1250 
1251 void QgsTextFormatWidget::mShapeSVGPathLineEdit_textChanged( const QString &text )
1252 {
1253  updateSvgWidgets( text );
1254 }
1255 
1257 {
1258  int numOptionsChecked = ( chkLineAbove->isChecked() ? 1 : 0 ) +
1259  ( chkLineBelow->isChecked() ? 1 : 0 ) +
1260  ( chkLineOn->isChecked() ? 1 : 0 );
1261 
1262  if ( numOptionsChecked == 1 )
1263  {
1264  //prevent unchecking last option
1265  chkLineAbove->setEnabled( !chkLineAbove->isChecked() );
1266  chkLineBelow->setEnabled( !chkLineBelow->isChecked() );
1267  chkLineOn->setEnabled( !chkLineOn->isChecked() );
1268  }
1269  else
1270  {
1271  chkLineAbove->setEnabled( true );
1272  chkLineBelow->setEnabled( true );
1273  chkLineOn->setEnabled( true );
1274  }
1275 }
1276 
1277 void QgsTextFormatWidget::onSubstitutionsChanged( const QgsStringReplacementCollection &substitutions )
1278 {
1279  mSubstitutions = substitutions;
1280  emit widgetChanged();
1281 }
1282 
1283 void QgsTextFormatWidget::previewScaleChanged( double scale )
1284 {
1285  lblFontPreview->setScale( scale );
1286 }
1287 
1288 void QgsTextFormatWidget::updateSvgWidgets( const QString &svgPath )
1289 {
1290  if ( mShapeSVGPathLineEdit->text() != svgPath )
1291  {
1292  mShapeSVGPathLineEdit->setText( svgPath );
1293  }
1294 
1295  QString resolvedPath;
1296  bool validSVG = true;
1297  if ( ! svgPath.startsWith( QLatin1String( "base64:" ), Qt::CaseInsensitive ) )
1298  {
1299  resolvedPath = QgsSymbolLayerUtils::svgSymbolNameToPath( svgPath, QgsProject::instance()->pathResolver() );
1300  validSVG = QFileInfo::exists( resolvedPath );
1301  }
1302  else
1303  {
1304  resolvedPath = svgPath;
1305  validSVG = true;
1306  }
1307 
1308  // draw red text for path field if invalid (path can't be resolved)
1309  mShapeSVGPathLineEdit->setStyleSheet( !validSVG ? QStringLiteral( "QLineEdit{ color: rgb(225, 0, 0); }" ) : QString() );
1310  mShapeSVGPathLineEdit->setToolTip( !validSVG ? tr( "File not found" ) : resolvedPath );
1311 
1312  QColor fill, stroke;
1313  double strokeWidth = 0.0;
1314  bool fillParam = false, strokeParam = false, strokeWidthParam = false;
1315  if ( validSVG )
1316  {
1317  QgsApplication::svgCache()->containsParams( resolvedPath, fillParam, fill, strokeParam, stroke, strokeWidthParam, strokeWidth );
1318  }
1319 
1320  mShapeSVGParamsBtn->setEnabled( validSVG && ( fillParam || strokeParam || strokeWidthParam ) );
1321 
1322  mShapeFillColorLabel->setEnabled( validSVG && fillParam );
1323  mShapeFillColorBtn->setEnabled( validSVG && fillParam );
1324  mShapeFillColorDDBtn->setEnabled( validSVG && fillParam );
1325  if ( mLoadSvgParams && validSVG && fillParam )
1326  mShapeFillColorBtn->setColor( fill );
1327 
1328  mShapeStrokeColorLabel->setEnabled( validSVG && strokeParam );
1329  mShapeStrokeColorBtn->setEnabled( validSVG && strokeParam );
1330  mShapeStrokeColorDDBtn->setEnabled( validSVG && strokeParam );
1331  if ( mLoadSvgParams && validSVG && strokeParam )
1332  mShapeStrokeColorBtn->setColor( stroke );
1333 
1334  mShapeStrokeWidthLabel->setEnabled( validSVG && strokeWidthParam );
1335  mShapeStrokeWidthSpnBx->setEnabled( validSVG && strokeWidthParam );
1336  mShapeStrokeWidthDDBtn->setEnabled( validSVG && strokeWidthParam );
1337  if ( mLoadSvgParams && validSVG && strokeWidthParam )
1338  mShapeStrokeWidthSpnBx->setValue( strokeWidth );
1339 
1340  // TODO: fix overriding SVG symbol's stroke width units in QgsSvgCache
1341  // currently broken, fall back to symbol's
1342  //mShapeStrokeWidthUnitWidget->setEnabled( validSVG && strokeWidthParam );
1343  //mShapeStrokeUnitsDDBtn->setEnabled( validSVG && strokeWidthParam );
1344  mShapeSVGUnitsLabel->setEnabled( validSVG && strokeWidthParam );
1345 }
1346 
1347 void QgsTextFormatWidget::mShapeSVGSelectorBtn_clicked()
1348 {
1349  QgsSvgSelectorDialog svgDlg( this );
1350  svgDlg.setWindowTitle( tr( "Select SVG file" ) );
1351  svgDlg.svgSelector()->setSvgPath( mShapeSVGPathLineEdit->text().trimmed() );
1352 
1353  if ( svgDlg.exec() == QDialog::Accepted )
1354  {
1355  QString svgPath = svgDlg.svgSelector()->currentSvgPath();
1356  if ( !svgPath.isEmpty() )
1357  {
1358  mShapeSVGPathLineEdit->setText( svgPath );
1359  updatePreview();
1360  }
1361  }
1362 }
1363 
1364 void QgsTextFormatWidget::mShapeSVGParamsBtn_clicked()
1365 {
1366  QString svgPath = mShapeSVGPathLineEdit->text();
1367  mLoadSvgParams = true;
1368  updateSvgWidgets( svgPath );
1369  mLoadSvgParams = false;
1370 }
1371 
1372 void QgsTextFormatWidget::mShapeRotationCmbBx_currentIndexChanged( int index )
1373 {
1374  mShapeRotationDblSpnBx->setEnabled( ( QgsTextBackgroundSettings::RotationType )index != QgsTextBackgroundSettings::RotationSync );
1375  mShapeRotationDDBtn->setEnabled( ( QgsTextBackgroundSettings::RotationType )index != QgsTextBackgroundSettings::RotationSync );
1376 }
1377 
1378 void QgsTextFormatWidget::mPreviewTextEdit_textChanged( const QString &text )
1379 {
1380  lblFontPreview->setText( text );
1381  updatePreview();
1382 }
1383 
1384 void QgsTextFormatWidget::mPreviewTextBtn_clicked()
1385 {
1386  mPreviewTextEdit->setText( QStringLiteral( "Lorem Ipsum" ) );
1387  updatePreview();
1388 }
1389 
1390 void QgsTextFormatWidget::mPreviewBackgroundBtn_colorChanged( const QColor &color )
1391 {
1392  setPreviewBackground( color );
1393 }
1394 
1395 void QgsTextFormatWidget::mDirectSymbLeftToolBtn_clicked()
1396 {
1397  bool gotChar = false;
1398  QChar dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ) );
1399 
1400  if ( !gotChar )
1401  return;
1402 
1403  if ( !dirSymb.isNull() )
1404  mDirectSymbLeftLineEdit->setText( QString( dirSymb ) );
1405 }
1406 
1407 void QgsTextFormatWidget::mDirectSymbRightToolBtn_clicked()
1408 {
1409  bool gotChar = false;
1410  QChar dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ) );
1411 
1412  if ( !gotChar )
1413  return;
1414 
1415  if ( !dirSymb.isNull() )
1416  mDirectSymbRightLineEdit->setText( QString( dirSymb ) );
1417 }
1418 
1419 void QgsTextFormatWidget::mChkNoObstacle_toggled( bool active )
1420 {
1421  mPolygonObstacleTypeFrame->setEnabled( active );
1422  mObstaclePriorityFrame->setEnabled( active );
1423 }
1424 
1425 void QgsTextFormatWidget::chkLineOrientationDependent_toggled( bool active )
1426 {
1427  if ( active )
1428  {
1429  chkLineAbove->setText( tr( "Left of line" ) );
1430  chkLineBelow->setText( tr( "Right of line" ) );
1431  }
1432  else
1433  {
1434  chkLineAbove->setText( tr( "Above line" ) );
1435  chkLineBelow->setText( tr( "Below line" ) );
1436  }
1437 }
1438 
1439 
1440 void QgsTextFormatWidget::mToolButtonConfigureSubstitutes_clicked()
1441 {
1443  if ( panel && panel->dockMode() )
1444  {
1446  widget->setPanelTitle( tr( "Substitutions" ) );
1447  widget->setSubstitutions( mSubstitutions );
1448  connect( widget, &QgsSubstitutionListWidget::substitutionsChanged, this, &QgsTextFormatWidget::onSubstitutionsChanged );
1449  panel->openPanel( widget );
1450  return;
1451  }
1452 
1453  QgsSubstitutionListDialog dlg( this );
1455  if ( dlg.exec() == QDialog::Accepted )
1456  {
1457  mSubstitutions = dlg.substitutions();
1458  emit widgetChanged();
1459  }
1460 }
1461 
1462 void QgsTextFormatWidget::showBackgroundRadius( bool show )
1463 {
1464  mShapeRadiusLabel->setVisible( show );
1465  mShapeRadiusXDbSpnBx->setVisible( show );
1466 
1467  mShapeRadiusYDbSpnBx->setVisible( show );
1468 
1469  mShapeRadiusUnitWidget->setVisible( show );
1470 
1471  mShapeRadiusDDBtn->setVisible( show && mWidgetMode == Labeling );
1472  mShapeRadiusUnitsDDBtn->setVisible( show && mWidgetMode == Labeling );
1473 }
1474 
1475 void QgsTextFormatWidget::showBackgroundPenStyle( bool show )
1476 {
1477  mShapePenStyleLabel->setVisible( show );
1478  mShapePenStyleCmbBx->setVisible( show );
1479 
1480  mShapePenStyleDDBtn->setVisible( show && mWidgetMode == Labeling );
1481 }
1482 
1484 {
1485  mCoordAlignmentFrame->setEnabled( enable );
1486 }
1487 
1488 
1489 //
1490 // QgsTextFormatDialog
1491 //
1492 
1493 QgsTextFormatDialog::QgsTextFormatDialog( const QgsTextFormat &format, QgsMapCanvas *mapCanvas, QWidget *parent, Qt::WindowFlags fl )
1494  : QDialog( parent, fl )
1495 {
1496  setWindowTitle( tr( "Text Settings" ) );
1497 
1498  mFormatWidget = new QgsTextFormatWidget( format, mapCanvas, this );
1499  mFormatWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
1500 
1501  QVBoxLayout *layout = new QVBoxLayout( this );
1502  layout->addWidget( mFormatWidget );
1503 
1504  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this );
1505  layout->addWidget( buttonBox );
1506 
1507  setLayout( layout );
1508 
1509  QgsSettings settings;
1510  restoreGeometry( settings.value( QStringLiteral( "Windows/TextFormatDialog/geometry" ) ).toByteArray() );
1511 
1512  connect( buttonBox->button( QDialogButtonBox::Ok ), &QAbstractButton::clicked, this, &QDialog::accept );
1513  connect( buttonBox->button( QDialogButtonBox::Cancel ), &QAbstractButton::clicked, this, &QDialog::reject );
1514 }
1515 
1517 {
1518  QgsSettings settings;
1519  settings.setValue( QStringLiteral( "Windows/TextFormatDialog/geometry" ), saveGeometry() );
1520 }
1521 
1523 {
1524  return mFormatWidget->format();
1525 }
1526 
1528  : QgsPanelWidgetWrapper( new QgsTextFormatWidget( format, mapCanvas ), parent )
1529 {
1530  mFormatWidget = qobject_cast< QgsTextFormatWidget * >( widget() );
1531  connect( mFormatWidget, &QgsTextFormatWidget::widgetChanged, this, &QgsPanelWidget::widgetChanged );
1532 }
1533 
1535 {
1536  return mFormatWidget->format();
1537 }
1538 
1540 {
1541  mFormatWidget->setDockMode( dockMode );
1543 }
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the buffer.
static QgsSvgCache * svgCache()
Returns the application&#39;s SVG cache, used for caching SVG images and handling parameter replacement w...
QColor strokeColor() const
Returns the color used for outlining the background shape.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
void setScale(int scale)
Sets the scaling used for the drop shadow (in percentage of original size).
Meters value as Map units.
Definition: qgsunittypes.h:120
void setLineHeight(double height)
Sets the line height for text.
void setRadiiUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape&#39;s radii.
void setStrokeWidth(double width)
Sets the width of the shape&#39;s stroke (stroke).
RotationType
Methods for determining the rotation of the background shape.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shadow offset distance.
void setSubstitutions(const QgsStringReplacementCollection &substitutions)
Sets the list of substitutions to show in the widget.
void setOpacity(double opacity)
Sets the text&#39;s opacity.
void setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape stroke width.
void setOffsetUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shadow&#39;s offset.
QWidget * widget()
Returns the internal widget that is wrapped in this panel.
QgsTextShadowSettings::ShadowPlacement shadowPlacement() const
Returns the placement for the drop shadow.
QSizeF radii() const
Returns the radii used for rounding the corners of shapes.
QSizeF size() const
Returns the size of the background shape.
double opacity() const
Returns the text&#39;s opacity.
bool dockMode()
Returns the dock mode state.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the shape&#39;s size.
bool fontFound() const
Returns true if the specified font was found on the system, or false if the font was not found and a ...
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the drop shadow.
QPointF offset() const
Returns the offset used for drawing the background shape.
QColor fillColor() const
Returns the color used for filing the background shape.
QgsMapUnitScale strokeWidthMapUnitScale() const
Returns the map unit scale object for the shape stroke width.
void setDockMode(bool enabled)
Sets whether the widget should be shown in a compact dock mode.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
A groupbox that collapses/expands when toggled and can save its collapsed and checked states...
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
ShadowPlacement
Placement positions for text shadow.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly...
Place direction symbols on below label.
QgsTextShadowSettings & shadow()
Returns a reference to the text drop shadow settings.
A combobox which lets the user select map scale from predefined list and highlights nearest to curren...
double blurRadius() const
Returns the blur radius for the shadow.
double opacity() const
Returns the background shape&#39;s opacity.
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:121
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the size.
void setStrokeColor(const QColor &color)
Sets the color used for outlining the background shape.
void setSize(double size)
Sets the size of the buffer.
double strokeWidth() const
Returns the width of the shape&#39;s stroke (stroke).
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
double offsetDistance() const
Returns the distance for offsetting the position of the shadow from the text.
QButtonGroup * mUpsidedownBtnGrp
Upside down labels button group.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the buffer.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
void collapsedStateChanged(bool collapsed)
Signal emitted when groupbox collapsed/expanded state is changed, and when first shown.
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
void setOffsetUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape&#39;s offset.
A cross platform button subclass for selecting colors.
QColor color() const
Returns the color that text will be rendered in.
void setFillBufferInterior(bool fill)
Sets whether the interior of the buffer will be filled in.
void setBlurRadius(double blurRadius)
Sets the blur radius for the shadow.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the buffer.
void setOpacity(double opacity)
Sets the shadow&#39;s opacity.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape size.
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs...
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void updateWidgetForFormat(const QgsTextFormat &format)
Updates the widget&#39;s state to reflect the settings in a QgsTextFormat.
QgsTextFormat format() const
Returns the current formatting settings defined by the widget.
A dialog for selecting a single character from a single font.
void setBackground(const QgsTextBackgroundSettings &backgroundSettings)
Sets the text&#39;s background settings.q.
Base class for any widget that can be shown as a inline panel.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the background shape.
void activated(bool isActive)
Emitted when the activated status of the widget changes.
Container for settings relating to a text background object.
A widget for customizing text formatting settings.
Percentage of another measurement (e.g., canvas size, feature size)
Definition: qgsunittypes.h:116
QgsMapUnitScale offsetMapUnitScale() const
Returns the map unit scale object for the shape offset.
void setRadiiMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape radii.
void setBlurRadiusUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shadow&#39;s blur radius.
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
void setBlurRadiusMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shadow blur radius.
QList< QgsUnitTypes::RenderUnit > RenderUnitList
List of render units.
Definition: qgsunittypes.h:184
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:73
Show labeling settings in addition to text formatting settings.
ShapeType type() const
Returns the type of background shape (e.g., square, ellipse, SVG).
void setOffset(QPointF offset)
Sets the offset used for drawing the background shape.
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs...
Qt::PenJoinStyle joinStyle() const
Returns the buffer join style.
Arranges candidates following the curvature of a line feature. Applies to line layers only...
QgsUnitTypes::DistanceUnit mapUnits() const
Gets units of map&#39;s geographical coordinates - used for scale calculation.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
void saveGeometry(QWidget *widget, const QString &keyName)
Save the wigget geometry into settings.
Place direction symbols on left/right of label.
bool restoreGeometry(QWidget *widget, const QString &keyName)
Restore the wigget geometry from settings.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the background shape.
QgsMapUnitScale offsetMapUnitScale() const
Returns the map unit scale object for the shadow offset distance.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the text.
A button for controlling property overrides which may apply to a widget.
QColor color() const
Returns the color of the drop shadow.
void setSize(double size)
Sets the size for rendered text.
void setOffsetDistance(double distance)
Sets the distance for offsetting the position of the shadow from the text.
void widgetChanged()
Emitted when the text format defined by the widget changes.
static QgsPaintEffect * defaultStack()
Returns a new effect stack consisting of a sensible selection of default effects. ...
QgsMapUnitScale blurRadiusMapUnitScale() const
Returns the map unit scale object for the shadow blur radius.
Offset distance applies from point geometry.
Default mode, show text formatting settings only.
bool fillBufferInterior() const
Returns whether the interior of the buffer will be filled in.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget...
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape offset.
void setBlurAlphaOnly(bool alphaOnly)
Sets whether only the alpha channel for the shadow should be blurred.
RotationType rotationType() const
Returns the method used for rotating the background shape.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the buffer size.
double scale() const
Returns the calculated map scale.
Show upside down for all labels, including dynamic ones.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the background shape.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the drop shadow.
void enableDataDefinedAlignment(bool enable)
Controls whether data defined alignment buttons are enabled.
void setColor(const QColor &color)
Sets the color for the drop shadow.
points (e.g., for font sizes)
Definition: qgsunittypes.h:118
void setEnabled(bool enabled)
Sets whether the text shadow will be drawn.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setFormat(const QgsTextFormat &format)
Sets the current formatting settings.
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
void setColor(const QColor &color)
Sets the color that text will be rendered in.
A widget which allows users to specify a list of substitutions to apply to a string, with options for exporting and importing substitution lists.
QgsMapUnitScale radiiMapUnitScale() const
Returns the map unit scale object for the shape radii.
QString svgFile() const
Returns the absolute path to the background SVG file, if set.
Qt::PenJoinStyle joinStyle() const
Returns the join style used for drawing the background shape.
void setNamedStyle(const QString &style)
Sets the named style for the font used for rendering text.
QgsTextBackgroundSettings & background()
Returns a reference to the text background settings.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
Upside-down labels (90 <= angle < 270) are shown upright.
SizeType
Methods for determining the background shape size.
double opacity() const
Returns the buffer opacity.
void updateLinePlacementOptions()
Updates line placement options to reflect current state of widget.
void setSvgPath(const QString &svgPath)
Accepts absolute paths.
void setSize(QSizeF size)
Sets the size of the background shape.
QgsStringReplacementCollection mSubstitutions
Text substitution list.
void setSettingGroup(const QString &group)
Sets this to a defined string to share save/restore states across different parent dialogs...
void setRadii(QSizeF radii)
Sets the radii used for rounding the corners of shapes.
void setPreviewBackground(const QColor &color)
Sets the background color for the text preview widget.
void widgetChanged()
Emitted when the widget state changes.
QgsUnitTypes::RenderUnit strokeWidthUnit() const
Returns the units used for the shape&#39;s stroke width.
Offset distance applies from rendered symbol bounds.
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
const QChar & selectCharacter(bool *gotChar, const QFont &font, const QString &style)
void setType(ShapeType type)
Sets the type of background shape to draw (e.g., square, ellipse, SVG).
Place direction symbols on above label.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the background shape.
QgsTextFormat format() const
Returns the current formatting settings defined by the widget.
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasStrokeParam, QColor &defaultStrokeColor, bool &hasStrokeWidthParam, double &defaultStrokeWidth) const
Tests if an svg file contains parameters for fill, stroke color, stroke width.
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units used for the shape&#39;s offset.
double rotation() const
Returns the rotation for the background shape, in degrees clockwise.
double lineHeight() const
Returns the line height for text.
QButtonGroup * mPlaceLineBtnGrp
Line placement button group.
void setEnabled(bool enabled)
Sets whether the text background will be drawn.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
int offsetAngle() const
Returns the angle for offsetting the position of the shadow from the text.
ShapeType
Background shape types.
void substitutionsChanged(const QgsStringReplacementCollection &substitutions)
Emitted when the substitution definitions change.
void colorChanged(const QColor &color)
Is emitted whenever a new color is set for the button.
QgsSvgSelectorWidget * svgSelector()
Returns pointer to the embedded SVG selector widget.
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point...
QgsTextFormat format() const
Returns the current formatting settings defined by the widget.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:212
static bool fontFamilyMatchOnSystem(const QString &family, QString *chosen=nullptr, bool *match=nullptr)
Check whether font family is on system.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the size.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units used for the shadow&#39;s offset.
bool enabled() const
Returns whether the shadow is enabled.
QgsTextFormatWidget(const QgsTextFormat &format=QgsTextFormat(), QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr)
Constructor for QgsTextFormatWidget.
QButtonGroup * mPlacePolygonBtnGrp
Polygon placement button group.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void changed()
Emitted when the paint effect properties change.
Container for settings relating to a text shadow.
A collection of string replacements (specified using QgsStringReplacement objects).
bool offsetGlobal() const
Returns true if the global shadow offset will be used.
QColor color() const
Returns the color of the buffer.
double size() const
Returns the size of the buffer.
QgsUnitTypes::RenderUnit radiiUnit() const
Returns the units used for the shape&#39;s radii.
Container for settings relating to a text buffer.
void setFillColor(const QColor &color)
Sets the color used for filing the background shape.
static bool updateFontViaStyle(QFont &f, const QString &fontstyle, bool fallback=false)
Updates font with named style and retain all font properties.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:430
double size() const
Returns the size for rendered text.
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape&#39;s stroke width.
bool enabled() const
Returns whether the background is enabled.
int mMinPixelLimit
Pixel size font limit.
SizeType sizeType() const
Returns the method used to determine the size of the background shape (e.g., fixed size or buffer aro...
void setSubstitutions(const QgsStringReplacementCollection &substitutions)
Sets the list of substitutions to show in the dialog.
QgsUnitTypes::RenderUnit blurRadiusUnit() const
Returns the units used for the shadow&#39;s blur radius.
bool enabled() const
Returns whether the buffer is enabled.
int scale() const
Returns the scaling used for the drop shadow (in percentage of original size).
Shape rotation is synced with text rotation.
QButtonGroup * mQuadrantBtnGrp
Quadrant button group.
void setShadowPlacement(QgsTextShadowSettings::ShadowPlacement placement)
Sets the placement for the drop shadow.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the text.
void setBuffer(const QgsTextBufferSettings &bufferSettings)
Sets the text&#39;s buffer settings.
void setShadow(const QgsTextShadowSettings &shadowSettings)
Sets the text&#39;s drop shadow settings.
A dialog which allows users to specify a list of substitutions to apply to a string, with options for exporting and importing substitution lists.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the buffer.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the shape size.
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol&#39;s path from its name.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
Show upside down when rotation is layer- or data-defined.
void updatePlacementWidgets()
Updates label placement options to reflect current state of widget.
Container for all settings relating to text rendering.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the buffer.
A widget displaying a combobox allowing the user to choose between various display units...
void setSvgFile(const QString &file)
Sets the path to the background SVG file.
bool blurAlphaOnly() const
Returns whether only the alpha channel for the shadow will be blurred.
void setOffsetGlobal(bool global)
Sets whether the global shadow offset should be used.
QButtonGroup * mPlacePointBtnGrp
Point placement button group.
void setOpacity(double opacity)
Sets the buffer opacity.
Square - buffered sizes only.
Wrapper widget for existing widgets which can&#39;t have the inheritance tree changed, e.g dialogs.
QgsStringReplacementCollection substitutions
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
QgsTextFormatPanelWidget(const QgsTextFormat &format, QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr)
Constructor for QgsTextFormatPanelWidget.
QString namedStyle() const
Returns the named style for the font used for rendering text (e.g., "bold").
QFont font() const
Returns the font used for rendering text.
void setRotationType(RotationType type)
Sets the method used for rotating the background shape.
void setColor(const QColor &color)
Sets the color for the buffer.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units used for the shape&#39;s size.
QButtonGroup * mDirectSymbBtnGrp
Symbol direction button group.
double opacity() const
Returns the shadow&#39;s opacity.
void setOpacity(double opacity)
Sets the background shape&#39;s opacity.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the background shape.
QString resolvedFontFamily() const
Returns the family for the resolved font, ie if the specified font was not found on the system this w...
QgsTextFormatDialog(const QgsTextFormat &format, QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Constructor for QgsTextFormatDialog.
void setOffsetAngle(int angle)
Sets the angle for offsetting the position of the shadow from the text.
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
void setRotation(double rotation)
Sets the rotation for the background shape, in degrees clockwise.
A widget for setting an opacity value.