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