QGIS API Documentation  3.27.0-Master (597e8eebd4)
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 #include "qgsstylesavedialog.h"
33 #include "qgsgui.h"
34 #include "qgsvectorlayer.h"
35 #include "qgsauxiliarystorage.h"
37 #include "qgshelp.h"
38 #include "qgsmarkersymbol.h"
39 #include "qgsfillsymbol.h"
40 #include "qgsiconutils.h"
42 #include "qgsconfig.h"
44 
45 #include <QButtonGroup>
46 #include <QMessageBox>
47 
48 QgsTextFormatWidget::QgsTextFormatWidget( const QgsTextFormat &format, QgsMapCanvas *mapCanvas, QWidget *parent, QgsVectorLayer *layer )
49  : QWidget( parent )
50  , mMapCanvas( mapCanvas )
51  , mLayer( layer )
52 {
53  initWidget();
54  setWidgetMode( Text );
57 }
58 
59 QgsTextFormatWidget::QgsTextFormatWidget( QgsMapCanvas *mapCanvas, QWidget *parent, Mode mode, QgsVectorLayer *layer )
60  : QWidget( parent )
61  , mMapCanvas( mapCanvas )
62  , mLayer( layer )
63  , mWidgetMode( mode )
64 {
65  initWidget();
66  if ( mode == Text )
68  setWidgetMode( mode );
69 }
70 
71 void QgsTextFormatWidget::initWidget()
72 {
73  setupUi( this );
74 
75  mGeometryGeneratorGroupBox->setCollapsed( true );
76 
77  connect( mShapeSVGPathLineEdit, &QLineEdit::textChanged, this, &QgsTextFormatWidget::mShapeSVGPathLineEdit_textChanged );
78  connect( mFontSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontSizeSpinBox_valueChanged );
79  connect( mFontFamilyCmbBx, &QFontComboBox::currentFontChanged, this, &QgsTextFormatWidget::mFontFamilyCmbBx_currentFontChanged );
80  connect( mFontStyleComboBox, &QComboBox::currentTextChanged, this, &QgsTextFormatWidget::mFontStyleComboBox_currentIndexChanged );
81  connect( mFontUnderlineBtn, &QToolButton::toggled, this, &QgsTextFormatWidget::mFontUnderlineBtn_toggled );
82  connect( mFontStrikethroughBtn, &QToolButton::toggled, this, &QgsTextFormatWidget::mFontStrikethroughBtn_toggled );
83  connect( mFontWordSpacingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontWordSpacingSpinBox_valueChanged );
84  connect( mFontLetterSpacingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontLetterSpacingSpinBox_valueChanged );
85  connect( mFontSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsTextFormatWidget::mFontSizeUnitWidget_changed );
86  connect( mFontMinPixelSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontMinPixelSpinBox_valueChanged );
87  connect( mFontMaxPixelSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontMaxPixelSpinBox_valueChanged );
88  connect( mBufferUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsTextFormatWidget::mBufferUnitWidget_changed );
89  connect( mMaskBufferUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsTextFormatWidget::mMaskBufferUnitWidget_changed );
90  connect( mCoordXDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::mCoordXDDBtn_changed );
91  connect( mCoordXDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::mCoordXDDBtn_activated );
92  connect( mCoordYDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::mCoordYDDBtn_changed );
93  connect( mCoordYDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::mCoordYDDBtn_activated );
94  connect( mCoordPointDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::mCoordPointDDBtn_changed );
95  connect( mCoordPointDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::mCoordPointDDBtn_activated );
96  connect( mShapeTypeCmbBx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::mShapeTypeCmbBx_currentIndexChanged );
97  connect( mShapeRotationCmbBx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::mShapeRotationCmbBx_currentIndexChanged );
98  connect( mShapeSVGParamsBtn, &QPushButton::clicked, this, &QgsTextFormatWidget::mShapeSVGParamsBtn_clicked );
99  connect( mShapeSVGSelectorBtn, &QPushButton::clicked, this, &QgsTextFormatWidget::mShapeSVGSelectorBtn_clicked );
100  connect( mPreviewTextEdit, &QLineEdit::textChanged, this, &QgsTextFormatWidget::mPreviewTextEdit_textChanged );
101  connect( mPreviewTextBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mPreviewTextBtn_clicked );
102  connect( mPreviewBackgroundBtn, &QgsColorButton::colorChanged, this, &QgsTextFormatWidget::mPreviewBackgroundBtn_colorChanged );
103  connect( mDirectSymbLeftToolBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mDirectSymbLeftToolBtn_clicked );
104  connect( mDirectSymbRightToolBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mDirectSymbRightToolBtn_clicked );
105  connect( chkLineOrientationDependent, &QCheckBox::toggled, this, &QgsTextFormatWidget::chkLineOrientationDependent_toggled );
106  connect( mToolButtonConfigureSubstitutes, &QToolButton::clicked, this, &QgsTextFormatWidget::mToolButtonConfigureSubstitutes_clicked );
107  connect( mKerningCheckBox, &QCheckBox::toggled, this, &QgsTextFormatWidget::kerningToggled );
108  connect( mComboOverlapHandling, qOverload< int >( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::overlapModeChanged );
109 
110  const int iconSize = QgsGuiUtils::scaleIconSize( 20 );
111  mOptionsTab->setIconSize( QSize( iconSize, iconSize ) );
112  mLabelingOptionsListWidget->setIconSize( QSize( iconSize, iconSize ) ) ;
113  const int iconSize32 = QgsGuiUtils::scaleIconSize( 32 );
114  const int iconSize24 = QgsGuiUtils::scaleIconSize( 24 );
115  const int iconSize18 = QgsGuiUtils::scaleIconSize( 18 );
116  const int iconSize16 = QgsGuiUtils::scaleIconSize( 16 );
117 
118  mPreviewTextBtn->setIconSize( QSize( iconSize16, iconSize16 ) );
119  mPointOffsetAboveLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
120  mPointOffsetAbove->setIconSize( QSize( iconSize32, iconSize18 ) );
121  mPointOffsetAboveRight->setIconSize( QSize( iconSize32, iconSize18 ) );
122  mPointOffsetLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
123  mPointOffsetOver ->setIconSize( QSize( iconSize32, iconSize18 ) );
124  mPointOffsetRight->setIconSize( QSize( iconSize32, iconSize18 ) );
125  mPointOffsetBelowLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
126  mPointOffsetBelow->setIconSize( QSize( iconSize32, iconSize18 ) );
127  mPointOffsetBelowRight->setIconSize( QSize( iconSize32, iconSize18 ) );
128  mLabelMinScale->setPixmap( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomOut.svg" ) ).pixmap( QSize( iconSize24, iconSize24 ) ) );
129  mLabelMaxScale->setPixmap( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomIn.svg" ) ).pixmap( QSize( iconSize24, iconSize24 ) ) );
130 
131  const int buttonSize = QgsGuiUtils::scaleIconSize( 24 );
132  mFontUnderlineBtn->setMinimumSize( buttonSize, buttonSize );
133  mFontUnderlineBtn->setMaximumSize( buttonSize, buttonSize );
134  mFontStrikethroughBtn->setMinimumSize( buttonSize, buttonSize );
135  mFontStrikethroughBtn->setMaximumSize( buttonSize, buttonSize );
136  mFontBoldBtn->setMinimumSize( buttonSize, buttonSize );
137  mFontBoldBtn->setMaximumSize( buttonSize, buttonSize );
138  mFontItalicBtn->setMinimumSize( buttonSize, buttonSize );
139  mFontItalicBtn->setMaximumSize( buttonSize, buttonSize );
140 
141  mPreviewScaleComboBox->setMapCanvas( mMapCanvas );
142  mPreviewScaleComboBox->setShowCurrentScaleButton( true );
143  connect( mPreviewScaleComboBox, &QgsScaleWidget::scaleChanged, this, &QgsTextFormatWidget::previewScaleChanged );
144 
145  const auto unitWidgets = findChildren<QgsUnitSelectionWidget *>();
146  for ( QgsUnitSelectionWidget *unitWidget : unitWidgets )
147  {
148  unitWidget->setMapCanvas( mMapCanvas );
149  }
177  mFontLineHeightSpinBox->setClearValue( 1.0 );
178  mShapeRotationDblSpnBx->setClearValue( 0.0 );
179  mShapeOffsetXSpnBx->setClearValue( 0.0 );
180  mShapeOffsetYSpnBx->setClearValue( 0.0 );
181  mPointOffsetXSpinBox->setClearValue( 0.0 );
182  mPointOffsetYSpinBox->setClearValue( 0.0 );
183  mPointAngleSpinBox->setClearValue( 0.0 );
184  mFontLetterSpacingSpinBox->setClearValue( 0.0 );
185  mFontWordSpacingSpinBox->setClearValue( 0.0 );
186  mZIndexSpinBox->setClearValue( 0.0 );
187  mLineDistanceSpnBx->setClearValue( 0.0 );
188  mSpinStretch->setClearValue( 100 );
189 
190  mOffsetTypeComboBox->addItem( tr( "From Point" ), static_cast< int >( Qgis::LabelOffsetType::FromPoint ) );
191  mOffsetTypeComboBox->addItem( tr( "From Symbol Bounds" ), static_cast< int >( Qgis::LabelOffsetType::FromSymbolBounds ) );
192 
193  mShapeTypeCmbBx->addItem( tr( "Rectangle" ), QgsTextBackgroundSettings::ShapeRectangle );
194  mShapeTypeCmbBx->addItem( tr( "Square" ), QgsTextBackgroundSettings::ShapeSquare );
195  mShapeTypeCmbBx->addItem( tr( "Ellipse" ), QgsTextBackgroundSettings::ShapeEllipse );
196  mShapeTypeCmbBx->addItem( tr( "Circle" ), QgsTextBackgroundSettings::ShapeCircle );
197  mShapeTypeCmbBx->addItem( tr( "SVG" ), QgsTextBackgroundSettings::ShapeSVG );
198  mShapeTypeCmbBx->addItem( tr( "Marker Symbol" ), QgsTextBackgroundSettings::ShapeMarkerSymbol );
199 
200  mComboOverlapHandling->addItem( tr( "Never Overlap" ), static_cast< int >( Qgis::LabelOverlapHandling::PreventOverlap ) );
201  mComboOverlapHandling->addItem( tr( "Allow Overlaps if Required" ), static_cast< int >( Qgis::LabelOverlapHandling::AllowOverlapIfRequired ) );
202  mComboOverlapHandling->addItem( tr( "Allow Overlaps without Penalty" ), static_cast< int >( Qgis::LabelOverlapHandling::AllowOverlapAtNoCost ) );
203 
204  updateAvailableShadowPositions();
205 
206  mBackgroundMarkerSymbolButton->setSymbolType( Qgis::SymbolType::Marker );
207  mBackgroundMarkerSymbolButton->setDialogTitle( tr( "Background Symbol" ) );
208  mBackgroundMarkerSymbolButton->registerExpressionContextGenerator( this );
209  mBackgroundMarkerSymbolButton->setMapCanvas( mMapCanvas );
210  mBackgroundFillSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
211  mBackgroundFillSymbolButton->setDialogTitle( tr( "Background Symbol" ) );
212  mBackgroundFillSymbolButton->registerExpressionContextGenerator( this );
213  mBackgroundFillSymbolButton->setMapCanvas( mMapCanvas );
214 
215  mCharDlg = new QgsCharacterSelectorDialog( this );
216 
217  mRefFont = lblFontPreview->font();
218 
219  // internal connections
220  connect( mShadowOffsetAngleDial, &QAbstractSlider::valueChanged, mShadowOffsetAngleSpnBx, &QSpinBox::setValue );
221  connect( mShadowOffsetAngleSpnBx, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), mShadowOffsetAngleDial, &QAbstractSlider::setValue );
222  connect( mLimitLabelChkBox, &QAbstractButton::toggled, mLimitLabelSpinBox, &QWidget::setEnabled );
223  connect( mCheckBoxSubstituteText, &QAbstractButton::toggled, mToolButtonConfigureSubstitutes, &QWidget::setEnabled );
224 
225  //connections to prevent users removing all line placement positions
226  connect( chkLineAbove, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
227  connect( chkLineBelow, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
228  connect( chkLineOn, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
229 
230  mTextOrientationComboBox->addItem( tr( "Horizontal" ), QgsTextFormat::HorizontalOrientation );
231  mTextOrientationComboBox->addItem( tr( "Vertical" ), QgsTextFormat::VerticalOrientation );
232 
233  populateFontCapitalsComboBox();
234 
235  // color buttons
236  mPreviewBackgroundBtn->setColorDialogTitle( tr( "Select Fill Color" ) );
237  mPreviewBackgroundBtn->setContext( QStringLiteral( "labeling" ) );
238  mPreviewBackgroundBtn->setColor( QColor( 255, 255, 255 ) );
239  btnTextColor->setColorDialogTitle( tr( "Select Text Color" ) );
240  btnTextColor->setContext( QStringLiteral( "labeling" ) );
241  btnTextColor->setDefaultColor( Qt::black );
242  btnBufferColor->setColorDialogTitle( tr( "Select Buffer Color" ) );
243  btnBufferColor->setContext( QStringLiteral( "labeling" ) );
244  btnBufferColor->setDefaultColor( Qt::white );
245  mShapeStrokeColorBtn->setColorDialogTitle( tr( "Select Stroke Color" ) );
246  mShapeStrokeColorBtn->setContext( QStringLiteral( "labeling" ) );
247  mShapeFillColorBtn->setColorDialogTitle( tr( "Select Fill Color" ) );
248  mShapeFillColorBtn->setContext( QStringLiteral( "labeling" ) );
249  mShadowColorBtn->setColorDialogTitle( tr( "Select Shadow Color" ) );
250  mShadowColorBtn->setContext( QStringLiteral( "labeling" ) );
251  mShadowColorBtn->setDefaultColor( Qt::black );
252 
253  mFontColorDDBtn->registerLinkedWidget( btnTextColor );
254  mBufferColorDDBtn->registerLinkedWidget( btnBufferColor );
255  mShapeStrokeColorDDBtn->registerLinkedWidget( mShapeStrokeColorBtn );
256  mShapeFillColorDDBtn->registerLinkedWidget( mShapeFillColorBtn );
257  mShadowColorDDBtn->registerLinkedWidget( mShadowColorBtn );
258 
259  // set up quadrant offset button group
260  mQuadrantBtnGrp = new QButtonGroup( this );
261  mQuadrantBtnGrp->addButton( mPointOffsetAboveLeft, static_cast<int>( Qgis::LabelQuadrantPosition::AboveLeft ) );
262  mQuadrantBtnGrp->addButton( mPointOffsetAbove, static_cast<int>( Qgis::LabelQuadrantPosition::Above ) );
263  mQuadrantBtnGrp->addButton( mPointOffsetAboveRight, static_cast<int>( Qgis::LabelQuadrantPosition::AboveRight ) );
264  mQuadrantBtnGrp->addButton( mPointOffsetLeft, static_cast<int>( Qgis::LabelQuadrantPosition::Left ) );
265  mQuadrantBtnGrp->addButton( mPointOffsetOver, static_cast<int>( Qgis::LabelQuadrantPosition::Over ) );
266  mQuadrantBtnGrp->addButton( mPointOffsetRight, static_cast<int>( Qgis::LabelQuadrantPosition::Right ) );
267  mQuadrantBtnGrp->addButton( mPointOffsetBelowLeft, static_cast<int>( Qgis::LabelQuadrantPosition::BelowLeft ) );
268  mQuadrantBtnGrp->addButton( mPointOffsetBelow, static_cast<int>( Qgis::LabelQuadrantPosition::Below ) );
269  mQuadrantBtnGrp->addButton( mPointOffsetBelowRight, static_cast<int>( Qgis::LabelQuadrantPosition::BelowRight ) );
270  mQuadrantBtnGrp->setExclusive( true );
271 
272  // setup direction symbol(s) button group
273  mDirectSymbBtnGrp = new QButtonGroup( this );
274  mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnLR, static_cast<int>( QgsLabelLineSettings::DirectionSymbolPlacement::SymbolLeftRight ) );
275  mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnAbove, static_cast<int>( QgsLabelLineSettings::DirectionSymbolPlacement::SymbolAbove ) );
276  mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnBelow, static_cast<int>( QgsLabelLineSettings::DirectionSymbolPlacement::SymbolBelow ) );
277  mDirectSymbBtnGrp->setExclusive( true );
278 
279  // upside-down labels button group
280  mUpsidedownBtnGrp = new QButtonGroup( this );
281  mUpsidedownBtnGrp->addButton( mUpsidedownRadioOff, static_cast<int>( Qgis::UpsideDownLabelHandling::FlipUpsideDownLabels ) );
282  mUpsidedownBtnGrp->addButton( mUpsidedownRadioDefined, static_cast<int>( Qgis::UpsideDownLabelHandling::AllowUpsideDownWhenRotationIsDefined ) );
283  mUpsidedownBtnGrp->addButton( mUpsidedownRadioAll, static_cast<int>( Qgis::UpsideDownLabelHandling::AlwaysAllowUpsideDown ) );
284  mUpsidedownBtnGrp->setExclusive( true );
285 
286  //mShapeCollisionsChkBx->setVisible( false ); // until implemented
287 
288  // post updatePlacementWidgets() connections
289  connect( chkLineAbove, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updatePlacementWidgets );
290  connect( chkLineBelow, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updatePlacementWidgets );
291  connect( mCheckAllowLabelsOutsidePolygons, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updatePlacementWidgets );
292  connect( mAllowOutsidePolygonsDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::updatePlacementWidgets );
293 
294  connect( mPlacementModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::updatePlacementWidgets );
295 
296  // Global settings group for groupboxes' saved/restored collapsed state
297  // maintains state across different dialogs
298  const auto groupBoxes = findChildren<QgsCollapsibleGroupBox *>();
299  for ( QgsCollapsibleGroupBox *grpbox : groupBoxes )
300  {
301  grpbox->setSettingGroup( QStringLiteral( "mAdvLabelingDlg" ) );
302  }
303 
304  connect( groupBox_mPreview, &QgsCollapsibleGroupBoxBasic::collapsedStateChanged, this, &QgsTextFormatWidget::collapseSample );
305 
306  // get rid of annoying outer focus rect on Mac
307  mLabelingOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect, false );
308 
309  const QgsSettings settings;
310 
311  // reset horiz stretch of left side of options splitter (set to 1 for previewing in Qt Designer)
312  QSizePolicy policy( mLabelingOptionsListFrame->sizePolicy() );
313  policy.setHorizontalStretch( 0 );
314  mLabelingOptionsListFrame->setSizePolicy( policy );
315  if ( !settings.contains( QStringLiteral( "/Windows/Labeling/OptionsSplitState" ) ) )
316  {
317  // set left list widget width on initial showing
318  QList<int> splitsizes;
319  splitsizes << 115;
320  mLabelingOptionsSplitter->setSizes( splitsizes );
321  }
322 
323  // set up reverse connection from stack to list
324  connect( mLabelStackedWidget, &QStackedWidget::currentChanged, this, &QgsTextFormatWidget::optionsStackedWidget_CurrentChanged );
325 
326  // restore dialog, splitters and current tab
327  mFontPreviewSplitter->restoreState( settings.value( QStringLiteral( "Windows/Labeling/FontPreviewSplitState" ) ).toByteArray() );
328  mLabelingOptionsSplitter->restoreState( settings.value( QStringLiteral( "Windows/Labeling/OptionsSplitState" ) ).toByteArray() );
329 
330  mLabelingOptionsListWidget->setCurrentRow( settings.value( QStringLiteral( "Windows/Labeling/Tab" ), 0 ).toInt() );
331 
332  mBufferEffect.reset( QgsPaintEffectRegistry::defaultStack() );
333  connect( mBufferEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
334  mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );
335 
336  mMaskEffect.reset( QgsPaintEffectRegistry::defaultStack() );
337  connect( mMaskEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
338  mMaskEffectWidget->setPaintEffect( mMaskEffect.get() );
339 
340  mBackgroundEffect.reset( QgsPaintEffectRegistry::defaultStack() );
341  connect( mBackgroundEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
342  mBackgroundEffectWidget->setPaintEffect( mBackgroundEffect.get() );
343 
344  overlapModeChanged();
345 
346 #ifndef HAS_KDE_QT5_FONT_STRETCH_FIX
347  mLabelStretch->hide();
348  mSpinStretch->hide();
349  mFontStretchDDBtn->hide();
350 #endif
351 
352  setDockMode( false );
353 
354  QList<QWidget *> widgets;
355  widgets << btnBufferColor
356  << btnTextColor
357  << chkLabelPerFeaturePart
358  << chkLineAbove
359  << chkLineBelow
360  << chkLineOn
361  << chkLineOrientationDependent
362  << chkMergeLines
363  << chkPreserveRotation
364  << comboBlendMode
365  << comboBufferBlendMode
366  << mBufferDrawChkBx
367  << mBufferJoinStyleComboBox
368  << mBufferTranspFillChbx
369  << mBufferOpacityWidget
370  << mCentroidInsideCheckBox
371  << mChkNoObstacle
372  << mCoordRotationUnitComboBox
373  << mDirectSymbChkBx
374  << mDirectSymbLeftLineEdit
375  << mDirectSymbRevChkBx
376  << mDirectSymbRightLineEdit
377  << mFitInsidePolygonCheckBox
378  << mFontCapitalsComboBox
379  << mFontLetterSpacingSpinBox
380  << mFontLimitPixelChkBox
381  << mFontLineHeightSpinBox
382  << mFontMaxPixelSpinBox
383  << mFontMinPixelSpinBox
384  << mFontMultiLineAlignComboBox
385  << mFontSizeSpinBox
386  << mFontStyleComboBox
387  << mTextOrientationComboBox
388  << mTextOpacityWidget
389  << mSpinStretch
390  << mFontWordSpacingSpinBox
391  << mFormatNumChkBx
392  << mFormatNumDecimalsSpnBx
393  << mFormatNumPlusSignChkBx
394  << mLimitLabelChkBox
395  << mLimitLabelSpinBox
396  << mLineDistanceSpnBx
397  << mLineDistanceUnitWidget
398  << mMaxCharAngleInDSpinBox
399  << mMaxCharAngleOutDSpinBox
400  << mMinSizeSpinBox
401  << mOffsetTypeComboBox
402  << mCheckAllowDegradedPlacement
403  << mComboOverlapHandling
404  << mPointAngleSpinBox
405  << mPointOffsetUnitWidget
406  << mPointOffsetXSpinBox
407  << mPointOffsetYSpinBox
408  << mPreviewBackgroundBtn
409  << mPreviewTextEdit
410  << mPrioritySlider
411  << mRepeatDistanceSpinBox
412  << mRepeatDistanceUnitWidget
413  << mOverrunDistanceSpinBox
414  << mOverrunDistanceUnitWidget
415  << mScaleBasedVisibilityChkBx
416  << mMaxScaleWidget
417  << mMinScaleWidget
418  << mShadowBlendCmbBx
419  << mShadowColorBtn
420  << mShadowDrawChkBx
421  << mShadowOffsetAngleSpnBx
422  << mShadowOffsetGlobalChkBx
423  << mShadowOffsetSpnBx
424  << mShadowOffsetUnitWidget
425  << mShadowRadiusAlphaChkBx
426  << mShadowRadiusDblSpnBx
427  << mShadowRadiusUnitWidget
428  << mShadowScaleSpnBx
429  << mShadowOpacityWidget
430  << mShadowUnderCmbBx
431  << mShapeBlendCmbBx
432  << mShapeStrokeColorBtn
433  << mShapeStrokeWidthSpnBx
434  << mShapeStrokeWidthUnitWidget
435  << mShapeDrawChkBx
436  << mShapeFillColorBtn
437  << mShapeOffsetXSpnBx
438  << mShapeOffsetYSpnBx
439  << mShapeOffsetUnitWidget
440  << mShapeRadiusXDbSpnBx
441  << mShapeRadiusYDbSpnBx
442  << mShapeRotationCmbBx
443  << mShapeRotationDblSpnBx
444  << mShapeRadiusUnitWidget
445  << mShapeSVGPathLineEdit
446  << mShapeSizeCmbBx
447  << mShapeSizeUnitWidget
448  << mShapeSizeXSpnBx
449  << mShapeSizeYSpnBx
450  << mBackgroundOpacityWidget
451  << mShapeTypeCmbBx
452  << mZIndexSpinBox
453  << spinBufferSize
454  << wrapCharacterEdit
455  << mAutoWrapLengthSpinBox
456  << mAutoWrapTypeComboBox
457  << mCentroidRadioVisible
458  << mCentroidRadioWhole
459  << mDirectSymbRadioBtnAbove
460  << mDirectSymbRadioBtnBelow
461  << mDirectSymbRadioBtnLR
462  << mUpsidedownRadioAll
463  << mUpsidedownRadioDefined
464  << mUpsidedownRadioOff
465  << mPlacementModeComboBox
466  << mFieldExpressionWidget
467  << mCheckBoxSubstituteText
468  << mGeometryGeneratorGroupBox
469  << mGeometryGenerator
470  << mGeometryGeneratorType
471  << mBackgroundMarkerSymbolButton
472  << mBackgroundFillSymbolButton
473  << mCalloutsDrawCheckBox
474  << mCalloutStyleComboBox
475  << mKerningCheckBox
476  << mEnableMaskChkBx
477  << mMaskJoinStyleComboBox
478  << mMaskBufferSizeSpinBox
479  << mMaskOpacityWidget
480  << mCheckAllowLabelsOutsidePolygons
481  << mHtmlFormattingCheckBox;
482 
483  connectValueChanged( widgets, SLOT( updatePreview() ) );
484 
485  connect( mQuadrantBtnGrp, qOverload< QAbstractButton * >( &QButtonGroup::buttonClicked ), this, &QgsTextFormatWidget::updatePreview );
486 
487  connect( mBufferDrawDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::updateBufferFrameStatus );
488  connect( mBufferDrawChkBx, &QCheckBox::stateChanged, this, [ = ]( int )
489  {
490  updateBufferFrameStatus();
491  } );
492  connect( mShapeDrawDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::updateShapeFrameStatus );
493  connect( mShapeDrawChkBx, &QCheckBox::stateChanged, this, [ = ]( int )
494  {
495  updateShapeFrameStatus();
496  } );
497  connect( mShadowDrawDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::updateShadowFrameStatus );
498  connect( mShadowDrawChkBx, &QCheckBox::stateChanged, this, [ = ]( int )
499  {
500  updateShadowFrameStatus();
501  } );
502  connect( mCalloutDrawDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::updateCalloutFrameStatus );
503  connect( mCalloutsDrawCheckBox, &QCheckBox::stateChanged, this, [ = ]( int )
504  {
505  updateCalloutFrameStatus();
506  } );
507 
508  mGeometryGeneratorType->addItem( QgsIconUtils::iconForWkbType( QgsWkbTypes::Polygon ), tr( "Polygon / MultiPolygon" ), QgsWkbTypes::GeometryType::PolygonGeometry );
509  mGeometryGeneratorType->addItem( QgsIconUtils::iconForWkbType( QgsWkbTypes::LineString ), tr( "LineString / MultiLineString" ), QgsWkbTypes::GeometryType::LineGeometry );
510  mGeometryGeneratorType->addItem( QgsIconUtils::iconForWkbType( QgsWkbTypes::Point ), tr( "Point / MultiPoint" ), QgsWkbTypes::GeometryType::PointGeometry );
511 
512  // set correct initial tab to match displayed setting page
513  whileBlocking( mOptionsTab )->setCurrentIndex( mLabelStackedWidget->currentIndex() );
514  mOptionsTab->tabBar()->setUsesScrollButtons( true );
515 
516 
517  if ( mMapCanvas )
518  {
519  lblFontPreview->setMapUnits( mMapCanvas->mapSettings().mapUnits() );
520  mPreviewScaleComboBox->setScale( mMapCanvas->mapSettings().scale() );
521  }
522 
523  mTextFormatsListWidget->setStyle( QgsStyle::defaultStyle() );
524  mTextFormatsListWidget->setEntityType( QgsStyle::TextFormatEntity );
526  connect( mTextFormatsListWidget, &QgsStyleItemsListWidget::saveEntity, this, &QgsTextFormatWidget::saveFormat );
527 }
528 
529 void QgsTextFormatWidget::setWidgetMode( QgsTextFormatWidget::Mode mode )
530 {
531  mWidgetMode = mode;
532  switch ( mode )
533  {
534  case Labeling:
535  toggleDDButtons( true );
536  mTextFormatsListWidget->setEntityTypes( QList< QgsStyle::StyleEntity >() << QgsStyle::TextFormatEntity << QgsStyle::LabelSettingsEntity );
537  mTextOrientationComboBox->addItem( tr( "Rotation-based" ), QgsTextFormat::RotationBasedOrientation );
538  break;
539 
540  case Text:
541  {
542  const int prevIndex = mOptionsTab->currentIndex();
543  toggleDDButtons( true );
544  delete mLabelingOptionsListWidget->takeItem( 8 ); // rendering
545  delete mLabelingOptionsListWidget->takeItem( 7 ); // placement
546  delete mLabelingOptionsListWidget->takeItem( 6 ); // callouts
547  delete mLabelingOptionsListWidget->takeItem( 3 ); // mask
548  mOptionsTab->removeTab( 8 );
549  mOptionsTab->removeTab( 7 );
550  mOptionsTab->removeTab( 6 );
551  mOptionsTab->removeTab( 3 );
552  mLabelStackedWidget->removeWidget( mLabelPage_Rendering );
553  mLabelStackedWidget->removeWidget( mLabelPage_Callouts );
554  mLabelStackedWidget->removeWidget( mLabelPage_Mask );
555  mLabelStackedWidget->removeWidget( mLabelPage_Placement );
556  switch ( prevIndex )
557  {
558  case 0:
559  case 1:
560  case 2:
561  break;
562 
563  case 4: // background - account for removed mask tab
564  case 5: // shadow
565  mLabelStackedWidget->setCurrentIndex( prevIndex - 1 );
566  mOptionsTab->setCurrentIndex( prevIndex - 1 );
567  break;
568 
569  case 3: // mask
570  case 6: // callouts
571  case 7: // placement
572  case 8: // rendering
573  mLabelStackedWidget->setCurrentIndex( 0 );
574  mOptionsTab->setCurrentIndex( 0 );
575  break;
576  }
577 
578  frameLabelWith->hide();
579  mDirectSymbolsFrame->hide();
580  mFormatNumFrame->hide();
581  mFormatNumChkBx->hide();
582  mFormatNumDDBtn->hide();
583  mCheckBoxSubstituteText->hide();
584  mToolButtonConfigureSubstitutes->hide();
585  mLabelWrapOnCharacter->hide();
586  wrapCharacterEdit->hide();
587  mWrapCharDDBtn->hide();
588  mLabelWrapLinesTo->hide();
589  mAutoWrapLengthSpinBox->hide();
590  mAutoWrapLengthDDBtn->hide();
591  mAutoWrapTypeComboBox->hide();
592  mFontMultiLineLabel->hide();
593  mFontMultiLineAlignComboBox->hide();
594  mFontMultiLineAlignDDBtn->hide();
595 
596  mTextOrientationComboBox->removeItem( mTextOrientationComboBox->findData( QgsTextFormat::RotationBasedOrientation ) );
597  break;
598  }
599  }
600 }
601 
602 void QgsTextFormatWidget::toggleDDButtons( bool visible )
603 {
604  const auto buttons = findChildren< QgsPropertyOverrideButton * >();
605  for ( QgsPropertyOverrideButton *button : buttons )
606  {
607 #ifndef HAS_KDE_QT5_FONT_STRETCH_FIX
608  if ( button == mFontStretchDDBtn )
609  continue; // always hidden
610 #endif
611  button->setVisible( visible );
612  }
613 }
614 
616 {
617  mOptionsTab->setVisible( enabled );
618  mOptionsTab->setTabToolTip( 0, tr( "Text" ) );
619  mOptionsTab->setTabToolTip( 1, tr( "Formatting" ) );
620  mOptionsTab->setTabToolTip( 2, tr( "Buffer" ) );
621  mOptionsTab->setTabToolTip( 3, tr( "Mask" ) );
622  mOptionsTab->setTabToolTip( 4, tr( "Background" ) );
623  mOptionsTab->setTabToolTip( 5, tr( "Shadow" ) );
624  mOptionsTab->setTabToolTip( 6, tr( "Callouts" ) );
625  mOptionsTab->setTabToolTip( 7, tr( "Placement" ) );
626  mOptionsTab->setTabToolTip( 8, tr( "Rendering" ) );
627 
628  mLabelingOptionsListFrame->setVisible( !enabled );
629  groupBox_mPreview->setVisible( !enabled );
630  mDockMode = enabled;
631 }
632 
633 void QgsTextFormatWidget::connectValueChanged( const QList<QWidget *> &widgets, const char *slot )
634 {
635  const auto constWidgets = widgets;
636  for ( QWidget *widget : constWidgets )
637  {
638  if ( QgsSymbolButton *w = qobject_cast<QgsSymbolButton *>( widget ) )
639  {
640  connect( w, SIGNAL( changed() ), this, slot );
641  }
642  else if ( QgsFieldExpressionWidget *w = qobject_cast< QgsFieldExpressionWidget *>( widget ) )
643  {
644  connect( w, SIGNAL( fieldChanged( QString ) ), this, slot );
645  }
646  else if ( QgsOpacityWidget *w = qobject_cast< QgsOpacityWidget *>( widget ) )
647  {
648  connect( w, SIGNAL( opacityChanged( double ) ), this, slot );
649  }
650  else if ( QgsScaleWidget *w = qobject_cast< QgsScaleWidget *>( widget ) )
651  {
652  connect( w, SIGNAL( scaleChanged( double ) ), this, slot );
653  }
654  else if ( QgsUnitSelectionWidget *w = qobject_cast<QgsUnitSelectionWidget *>( widget ) )
655  {
656  connect( w, SIGNAL( changed() ), this, slot );
657  }
658  else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
659  {
660  connect( w, SIGNAL( currentIndexChanged( int ) ), this, slot );
661  }
662  else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
663  {
664  connect( w, SIGNAL( valueChanged( int ) ), this, slot );
665  }
666  else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
667  {
668  connect( w, SIGNAL( valueChanged( double ) ), this, slot );
669  }
670  else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
671  {
672  connect( w, SIGNAL( colorChanged( QColor ) ), this, slot );
673  }
674  else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
675  {
676  connect( w, SIGNAL( toggled( bool ) ), this, slot );
677  }
678  else if ( QRadioButton *w = qobject_cast<QRadioButton *>( widget ) )
679  {
680  connect( w, SIGNAL( toggled( bool ) ), this, slot );
681  }
682  else if ( QLineEdit *w = qobject_cast<QLineEdit *>( widget ) )
683  {
684  connect( w, SIGNAL( textEdited( QString ) ), this, slot );
685  }
686  else if ( QSlider *w = qobject_cast<QSlider *>( widget ) )
687  {
688  connect( w, SIGNAL( valueChanged( int ) ), this, slot );
689  }
690  else if ( QGroupBox *w = qobject_cast<QGroupBox *>( widget ) )
691  {
692  connect( w, SIGNAL( toggled( bool ) ), this, slot );
693  }
694  else if ( QgsCodeEditorExpression *w = qobject_cast<QgsCodeEditorExpression *>( widget ) )
695  {
696  connect( w, SIGNAL( textChanged() ), this, slot );
697  }
698  else
699  {
700  QgsLogger::warning( QStringLiteral( "Could not create connection for widget %1" ).arg( widget->objectName() ) );
701  }
702  }
703 }
704 
706 {
707  // text style
708  registerDataDefinedButton( mFontDDBtn, QgsPalLayerSettings::Family );
709  registerDataDefinedButton( mFontStyleDDBtn, QgsPalLayerSettings::FontStyle );
710  registerDataDefinedButton( mFontUnderlineDDBtn, QgsPalLayerSettings::Underline );
711  registerDataDefinedButton( mFontStrikeoutDDBtn, QgsPalLayerSettings::Strikeout );
712  registerDataDefinedButton( mFontBoldDDBtn, QgsPalLayerSettings::Bold );
713  registerDataDefinedButton( mFontItalicDDBtn, QgsPalLayerSettings::Italic );
714  registerDataDefinedButton( mFontSizeDDBtn, QgsPalLayerSettings::Size );
715  registerDataDefinedButton( mFontUnitsDDBtn, QgsPalLayerSettings::FontSizeUnit );
716  registerDataDefinedButton( mFontColorDDBtn, QgsPalLayerSettings::Color );
717  registerDataDefinedButton( mFontOpacityDDBtn, QgsPalLayerSettings::FontOpacity );
718  registerDataDefinedButton( mFontCaseDDBtn, QgsPalLayerSettings::FontCase );
719  registerDataDefinedButton( mFontLetterSpacingDDBtn, QgsPalLayerSettings::FontLetterSpacing );
720  registerDataDefinedButton( mFontWordSpacingDDBtn, QgsPalLayerSettings::FontWordSpacing );
721  registerDataDefinedButton( mFontBlendModeDDBtn, QgsPalLayerSettings::FontBlendMode );
722  registerDataDefinedButton( mFontStretchDDBtn, QgsPalLayerSettings::FontStretchFactor );
723 
724  // text formatting
725  registerDataDefinedButton( mWrapCharDDBtn, QgsPalLayerSettings::MultiLineWrapChar );
726  registerDataDefinedButton( mAutoWrapLengthDDBtn, QgsPalLayerSettings::AutoWrapLength );
727  registerDataDefinedButton( mFontLineHeightDDBtn, QgsPalLayerSettings::MultiLineHeight );
728  registerDataDefinedButton( mFontMultiLineAlignDDBtn, QgsPalLayerSettings::MultiLineAlignment );
729  registerDataDefinedButton( mTextOrientationDDBtn, QgsPalLayerSettings::TextOrientation );
730 
731  registerDataDefinedButton( mDirectSymbDDBtn, QgsPalLayerSettings::DirSymbDraw );
732  mDirectSymbDDBtn->registerCheckedWidget( mDirectSymbChkBx );
733  registerDataDefinedButton( mDirectSymbLeftDDBtn, QgsPalLayerSettings::DirSymbLeft );
734  registerDataDefinedButton( mDirectSymbRightDDBtn, QgsPalLayerSettings::DirSymbRight );
735 
736  registerDataDefinedButton( mDirectSymbPlacementDDBtn, QgsPalLayerSettings::DirSymbPlacement );
737  registerDataDefinedButton( mDirectSymbRevDDBtn, QgsPalLayerSettings::DirSymbReverse );
738 
739  registerDataDefinedButton( mFormatNumDDBtn, QgsPalLayerSettings::NumFormat );
740  mFormatNumDDBtn->registerCheckedWidget( mFormatNumChkBx );
741  registerDataDefinedButton( mFormatNumDecimalsDDBtn, QgsPalLayerSettings::NumDecimals );
742  registerDataDefinedButton( mFormatNumPlusSignDDBtn, QgsPalLayerSettings::NumPlusSign );
743 
744  // text buffer
745  registerDataDefinedButton( mBufferDrawDDBtn, QgsPalLayerSettings::BufferDraw );
746  registerDataDefinedButton( mBufferSizeDDBtn, QgsPalLayerSettings::BufferSize );
747  registerDataDefinedButton( mBufferUnitsDDBtn, QgsPalLayerSettings::BufferUnit );
748  registerDataDefinedButton( mBufferColorDDBtn, QgsPalLayerSettings::BufferColor );
749  registerDataDefinedButton( mBufferOpacityDDBtn, QgsPalLayerSettings::BufferOpacity );
750  registerDataDefinedButton( mBufferJoinStyleDDBtn, QgsPalLayerSettings::BufferJoinStyle );
751  registerDataDefinedButton( mBufferBlendModeDDBtn, QgsPalLayerSettings::BufferBlendMode );
752 
753  // mask
754  registerDataDefinedButton( mEnableMaskDDBtn, QgsPalLayerSettings::MaskEnabled );
755  mEnableMaskDDBtn->registerCheckedWidget( mEnableMaskChkBx );
756  registerDataDefinedButton( mMaskBufferSizeDDBtn, QgsPalLayerSettings::MaskBufferSize );
757  registerDataDefinedButton( mMaskBufferUnitsDDBtn, QgsPalLayerSettings::MaskBufferUnit );
758  registerDataDefinedButton( mMaskOpacityDDBtn, QgsPalLayerSettings::MaskOpacity );
759  registerDataDefinedButton( mMaskJoinStyleDDBtn, QgsPalLayerSettings::MaskJoinStyle );
760 
761  // background
762  registerDataDefinedButton( mShapeDrawDDBtn, QgsPalLayerSettings::ShapeDraw );
763  mShapeDrawDDBtn->registerCheckedWidget( mShapeDrawChkBx );
764  registerDataDefinedButton( mShapeTypeDDBtn, QgsPalLayerSettings::ShapeKind );
765  registerDataDefinedButton( mShapeSVGPathDDBtn, QgsPalLayerSettings::ShapeSVGFile );
766  registerDataDefinedButton( mShapeSizeTypeDDBtn, QgsPalLayerSettings::ShapeSizeType );
767  registerDataDefinedButton( mShapeSizeXDDBtn, QgsPalLayerSettings::ShapeSizeX );
768  registerDataDefinedButton( mShapeSizeYDDBtn, QgsPalLayerSettings::ShapeSizeY );
769  registerDataDefinedButton( mShapeSizeUnitsDDBtn, QgsPalLayerSettings::ShapeSizeUnits );
770  registerDataDefinedButton( mShapeRotationTypeDDBtn, QgsPalLayerSettings::ShapeRotationType );
771  registerDataDefinedButton( mShapeRotationDDBtn, QgsPalLayerSettings::ShapeRotation );
772  registerDataDefinedButton( mShapeOffsetDDBtn, QgsPalLayerSettings::ShapeOffset );
773  registerDataDefinedButton( mShapeOffsetUnitsDDBtn, QgsPalLayerSettings::ShapeOffsetUnits );
774  registerDataDefinedButton( mShapeRadiusDDBtn, QgsPalLayerSettings::ShapeRadii );
775  registerDataDefinedButton( mShapeRadiusUnitsDDBtn, QgsPalLayerSettings::ShapeRadiiUnits );
776  registerDataDefinedButton( mShapeOpacityDDBtn, QgsPalLayerSettings::ShapeOpacity );
777  registerDataDefinedButton( mShapeBlendModeDDBtn, QgsPalLayerSettings::ShapeBlendMode );
778  registerDataDefinedButton( mShapeFillColorDDBtn, QgsPalLayerSettings::ShapeFillColor );
779  registerDataDefinedButton( mShapeStrokeColorDDBtn, QgsPalLayerSettings::ShapeStrokeColor );
780  registerDataDefinedButton( mShapeStrokeWidthDDBtn, QgsPalLayerSettings::ShapeStrokeWidth );
781  registerDataDefinedButton( mShapeStrokeUnitsDDBtn, QgsPalLayerSettings::ShapeStrokeWidthUnits );
782 
783  // drop shadows
784  registerDataDefinedButton( mShadowDrawDDBtn, QgsPalLayerSettings::ShadowDraw );
785  mShadowDrawDDBtn->registerCheckedWidget( mShadowDrawChkBx );
786  registerDataDefinedButton( mShadowUnderDDBtn, QgsPalLayerSettings::ShadowUnder );
787  registerDataDefinedButton( mShadowOffsetAngleDDBtn, QgsPalLayerSettings::ShadowOffsetAngle );
788  registerDataDefinedButton( mShadowOffsetDDBtn, QgsPalLayerSettings::ShadowOffsetDist );
789  registerDataDefinedButton( mShadowOffsetUnitsDDBtn, QgsPalLayerSettings::ShadowOffsetUnits );
790  registerDataDefinedButton( mShadowRadiusDDBtn, QgsPalLayerSettings::ShadowRadius );
791  registerDataDefinedButton( mShadowRadiusUnitsDDBtn, QgsPalLayerSettings::ShadowRadiusUnits );
792  registerDataDefinedButton( mShadowOpacityDDBtn, QgsPalLayerSettings::ShadowOpacity );
793  registerDataDefinedButton( mShadowScaleDDBtn, QgsPalLayerSettings::ShadowScale );
794  registerDataDefinedButton( mShadowColorDDBtn, QgsPalLayerSettings::ShadowColor );
795  registerDataDefinedButton( mShadowBlendDDBtn, QgsPalLayerSettings::ShadowBlendMode );
796 
797  // placement
798  registerDataDefinedButton( mCentroidDDBtn, QgsPalLayerSettings::CentroidWhole );
799  registerDataDefinedButton( mPointQuadOffsetDDBtn, QgsPalLayerSettings::OffsetQuad );
800  registerDataDefinedButton( mPointPositionOrderDDBtn, QgsPalLayerSettings::PredefinedPositionOrder );
801  registerDataDefinedButton( mLinePlacementFlagsDDBtn, QgsPalLayerSettings::LinePlacementOptions );
802  registerDataDefinedButton( mPointOffsetDDBtn, QgsPalLayerSettings::OffsetXY );
803  registerDataDefinedButton( mPointOffsetUnitsDDBtn, QgsPalLayerSettings::OffsetUnits );
804  registerDataDefinedButton( mLineDistanceDDBtn, QgsPalLayerSettings::LabelDistance );
805  registerDataDefinedButton( mLineDistanceUnitDDBtn, QgsPalLayerSettings::DistanceUnits );
806  registerDataDefinedButton( mPriorityDDBtn, QgsPalLayerSettings::Priority );
807  registerDataDefinedButton( mAllowOutsidePolygonsDDBtn, QgsPalLayerSettings::PolygonLabelOutside );
808  registerDataDefinedButton( mAllowInferiorPlacementDBtn, QgsPalLayerSettings::AllowDegradedPlacement );
809  registerDataDefinedButton( mOverlapHandlingDBtn, QgsPalLayerSettings::OverlapHandling );
810 
811  // TODO: is this necessary? maybe just use the data defined-only rotation?
812  //mPointAngleDDBtn, QgsPalLayerSettings::OffsetRotation,
813  // QgsPropertyOverrideButton::AnyType, QgsPropertyOverrideButton::double180RotDesc() );
814  registerDataDefinedButton( mMaxCharAngleDDBtn, QgsPalLayerSettings::CurvedCharAngleInOut );
815  registerDataDefinedButton( mRepeatDistanceDDBtn, QgsPalLayerSettings::RepeatDistance );
816  registerDataDefinedButton( mRepeatDistanceUnitDDBtn, QgsPalLayerSettings::RepeatDistanceUnit );
817  registerDataDefinedButton( mOverrunDistanceDDBtn, QgsPalLayerSettings::OverrunDistance );
818 
819  // data defined-only
820  registerDataDefinedButton( mCoordXDDBtn, QgsPalLayerSettings::PositionX );
821  registerDataDefinedButton( mCoordYDDBtn, QgsPalLayerSettings::PositionY );
822  registerDataDefinedButton( mCoordPointDDBtn, QgsPalLayerSettings::PositionPoint );
823  registerDataDefinedButton( mCoordAlignmentHDDBtn, QgsPalLayerSettings::Hali );
824  registerDataDefinedButton( mCoordAlignmentVDDBtn, QgsPalLayerSettings::Vali );
825  registerDataDefinedButton( mCoordRotationDDBtn, QgsPalLayerSettings::LabelRotation );
826 
827  updateDataDefinedAlignment();
828 
829  // rendering
830  const QString ddScaleVisInfo = tr( "Value &lt; 0 represents a scale closer than 1:1, e.g. -10 = 10:1<br>"
831  "Value of 0 disables the specific limit." );
832  registerDataDefinedButton( mScaleBasedVisibilityDDBtn, QgsPalLayerSettings::ScaleVisibility );
833  mScaleBasedVisibilityDDBtn->registerCheckedWidget( mScaleBasedVisibilityChkBx );
834  registerDataDefinedButton( mScaleBasedVisibilityMinDDBtn, QgsPalLayerSettings::MinimumScale );
835  mScaleBasedVisibilityMinDDBtn->setUsageInfo( ddScaleVisInfo );
836  registerDataDefinedButton( mScaleBasedVisibilityMaxDDBtn, QgsPalLayerSettings::MaximumScale );
837  mScaleBasedVisibilityMaxDDBtn->setUsageInfo( ddScaleVisInfo );
838 
839  registerDataDefinedButton( mFontLimitPixelDDBtn, QgsPalLayerSettings::FontLimitPixel );
840  mFontLimitPixelDDBtn->registerCheckedWidget( mFontLimitPixelChkBox );
841  registerDataDefinedButton( mFontMinPixelDDBtn, QgsPalLayerSettings::FontMinPixel );
842  registerDataDefinedButton( mFontMaxPixelDDBtn, QgsPalLayerSettings::FontMaxPixel );
843 
844  registerDataDefinedButton( mShowLabelDDBtn, QgsPalLayerSettings::Show );
845 
846  registerDataDefinedButton( mAlwaysShowDDBtn, QgsPalLayerSettings::AlwaysShow );
847 
848  registerDataDefinedButton( mIsObstacleDDBtn, QgsPalLayerSettings::IsObstacle );
849  registerDataDefinedButton( mZIndexDDBtn, QgsPalLayerSettings::ZIndex );
850 
851  registerDataDefinedButton( mCalloutDrawDDBtn, QgsPalLayerSettings::CalloutDraw );
852 
853  registerDataDefinedButton( mLabelAllPartsDDBtn, QgsPalLayerSettings::LabelAllParts );
854 }
855 
856 void QgsTextFormatWidget::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsPalLayerSettings::Property key )
857 {
859  if ( !mButtons.contains( key ) )
860  {
861  connect( button, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::updateProperty );
862  connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsTextFormatWidget::createAuxiliaryField );
863  button->registerExpressionContextGenerator( this );
864  mButtons[key] = button;
865  }
866 }
867 
869 {
870  const QgsTextBufferSettings buffer = format.buffer();
871  const QgsTextMaskSettings mask = format.mask();
872  const QgsTextBackgroundSettings background = format.background();
873  const QgsTextShadowSettings shadow = format.shadow();
874 
875  if ( mWidgetMode != Labeling )
876  {
878  }
879 
880  // buffer
881  mBufferDrawChkBx->setChecked( buffer.enabled() );
882  mBufferFrame->setEnabled( buffer.enabled() );
883  spinBufferSize->setValue( buffer.size() );
884  mBufferUnitWidget->setUnit( buffer.sizeUnit() );
885  mBufferUnitWidget->setMapUnitScale( buffer.sizeMapUnitScale() );
886  btnBufferColor->setColor( buffer.color() );
887  mBufferOpacityWidget->setOpacity( buffer.opacity() );
888  mBufferJoinStyleComboBox->setPenJoinStyle( buffer.joinStyle() );
889  mBufferTranspFillChbx->setChecked( buffer.fillBufferInterior() );
890  comboBufferBlendMode->setBlendMode( buffer.blendMode() );
891  if ( auto *lPaintEffect = buffer.paintEffect() )
892  mBufferEffect.reset( lPaintEffect->clone() );
893  else
894  {
895  mBufferEffect.reset( QgsPaintEffectRegistry::defaultStack() );
896  mBufferEffect->setEnabled( false );
897  }
898  mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );
899 
900  // mask
902  mEnableMaskChkBx->setChecked( mask.enabled() );
903  mMaskBufferSizeSpinBox->setValue( mask.size() );
904  mMaskBufferUnitWidget->setUnit( mask.sizeUnit() );
905  mMaskBufferUnitWidget->setMapUnitScale( mask.sizeMapUnitScale() );
906  mMaskOpacityWidget->setOpacity( mask.opacity() );
907  mMaskJoinStyleComboBox->setPenJoinStyle( mask.joinStyle() );
908  if ( auto *lPaintEffect = mask.paintEffect() )
909  mMaskEffect.reset( lPaintEffect->clone() );
910  else
911  {
912  mMaskEffect.reset( QgsPaintEffectRegistry::defaultStack() );
913  mMaskEffect->setEnabled( false );
914  }
915  mMaskEffectWidget->setPaintEffect( mMaskEffect.get() );
916 
917  mFontSizeUnitWidget->setUnit( format.sizeUnit() );
918  mFontSizeUnitWidget->setMapUnitScale( format.sizeMapUnitScale() );
919  mRefFont = format.font();
920  mFontSizeSpinBox->setValue( format.size() );
921  btnTextColor->setColor( format.color() );
922  whileBlocking( mSpinStretch )->setValue( format.stretchFactor() );
923  mTextOpacityWidget->setOpacity( format.opacity() );
924  comboBlendMode->setBlendMode( format.blendMode() );
925  mTextOrientationComboBox->setCurrentIndex( mTextOrientationComboBox->findData( format.orientation() ) );
926  mHtmlFormattingCheckBox->setChecked( format.allowHtmlFormatting() );
927 
928  mFontWordSpacingSpinBox->setValue( format.font().wordSpacing() );
929  mFontLetterSpacingSpinBox->setValue( format.font().letterSpacing() );
930  whileBlocking( mKerningCheckBox )->setChecked( format.font().kerning() );
931 
932  whileBlocking( mFontCapitalsComboBox )->setCurrentIndex( mFontCapitalsComboBox->findData( static_cast< int >( format.capitalization() ) ) );
934  updateFont( mRefFont );
935 
936  // show 'font not found' if substitution has occurred (should come after updateFont())
937  mFontMissingLabel->setVisible( !format.fontFound() );
938  if ( !format.fontFound() )
939  {
940  const QString missingTxt = tr( "%1 not found. Default substituted." );
941  QString txtPrepend = tr( "Chosen font" );
942  if ( !format.resolvedFontFamily().isEmpty() )
943  {
944  txtPrepend = QStringLiteral( "'%1'" ).arg( format.resolvedFontFamily() );
945  }
946  mFontMissingLabel->setText( missingTxt.arg( txtPrepend ) );
947 
948  // ensure user is sent to 'Text style' section to see notice
949  mLabelingOptionsListWidget->setCurrentRow( 0 );
950  whileBlocking( mOptionsTab )->setCurrentIndex( 0 );
951  }
952  mFontLineHeightSpinBox->setValue( format.lineHeight() );
953 
954  // shape background
955  mShapeDrawChkBx->setChecked( background.enabled() );
956  mShapeFrame->setEnabled( background.enabled() );
957  mShapeTypeCmbBx->blockSignals( true );
958  mShapeTypeCmbBx->setCurrentIndex( mShapeTypeCmbBx->findData( background.type() ) );
959  mShapeTypeCmbBx->blockSignals( false );
960  updateAvailableShadowPositions();
961  mShapeSVGPathLineEdit->setText( background.svgFile() );
962 
963  mShapeSizeCmbBx->setCurrentIndex( background.sizeType() );
964  mShapeSizeXSpnBx->setValue( background.size().width() );
965  mShapeSizeYSpnBx->setValue( background.size().height() );
966  mShapeSizeUnitWidget->setUnit( background.sizeUnit() );
967  mShapeSizeUnitWidget->setMapUnitScale( background.sizeMapUnitScale() );
968  mShapeRotationCmbBx->setCurrentIndex( background.rotationType() );
969  mShapeRotationDblSpnBx->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync );
970  mShapeRotationDDBtn->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync );
971  mShapeRotationDblSpnBx->setValue( background.rotation() );
972  mShapeOffsetXSpnBx->setValue( background.offset().x() );
973  mShapeOffsetYSpnBx->setValue( background.offset().y() );
974  mShapeOffsetUnitWidget->setUnit( background.offsetUnit() );
975  mShapeOffsetUnitWidget->setMapUnitScale( background.offsetMapUnitScale() );
976  mShapeRadiusXDbSpnBx->setValue( background.radii().width() );
977  mShapeRadiusYDbSpnBx->setValue( background.radii().height() );
978  mShapeRadiusUnitWidget->setUnit( background.radiiUnit() );
979  mShapeRadiusUnitWidget->setMapUnitScale( background.radiiMapUnitScale() );
980 
981  mShapeFillColorBtn->setColor( background.fillColor() );
982  mShapeStrokeColorBtn->setColor( background.strokeColor() );
983  mShapeStrokeWidthSpnBx->setValue( background.strokeWidth() );
984  mShapeStrokeWidthUnitWidget->setUnit( background.strokeWidthUnit() );
985  mShapeStrokeWidthUnitWidget->setMapUnitScale( background.strokeWidthMapUnitScale() );
986 
987  mBackgroundOpacityWidget->setOpacity( background.opacity() );
988  mShapeBlendCmbBx->setBlendMode( background.blendMode() );
989 
990  mLoadSvgParams = false;
991  mShapeTypeCmbBx_currentIndexChanged( background.type() ); // force update of shape background gui
992 
993  if ( auto *lPaintEffect = background.paintEffect() )
994  mBackgroundEffect.reset( lPaintEffect->clone() );
995  else
996  {
997  mBackgroundEffect.reset( QgsPaintEffectRegistry::defaultStack() );
998  mBackgroundEffect->setEnabled( false );
999  }
1000  mBackgroundEffectWidget->setPaintEffect( mBackgroundEffect.get() );
1001 
1002  mBackgroundMarkerSymbolButton->setSymbol( background.markerSymbol() ? background.markerSymbol()->clone() : QgsSymbol::defaultSymbol( QgsWkbTypes::PointGeometry ) );
1003  mBackgroundFillSymbolButton->setSymbol( background.fillSymbol() ? background.fillSymbol()->clone() : QgsSymbol::defaultSymbol( QgsWkbTypes::PolygonGeometry ) );
1004 
1005  // drop shadow
1006  mShadowDrawChkBx->setChecked( shadow.enabled() );
1007  mShadowFrame->setEnabled( shadow.enabled() );
1008  mShadowUnderCmbBx->setCurrentIndex( mShadowUnderCmbBx->findData( shadow.shadowPlacement() ) );
1009  mShadowOffsetAngleSpnBx->setValue( shadow.offsetAngle() );
1010  mShadowOffsetSpnBx->setValue( shadow.offsetDistance() );
1011  mShadowOffsetUnitWidget->setUnit( shadow.offsetUnit() );
1012  mShadowOffsetUnitWidget->setMapUnitScale( shadow.offsetMapUnitScale() );
1013  mShadowOffsetGlobalChkBx->setChecked( shadow.offsetGlobal() );
1014 
1015  mShadowRadiusDblSpnBx->setValue( shadow.blurRadius() );
1016  mShadowRadiusUnitWidget->setUnit( shadow.blurRadiusUnit() );
1017  mShadowRadiusUnitWidget->setMapUnitScale( shadow.blurRadiusMapUnitScale() );
1018  mShadowRadiusAlphaChkBx->setChecked( shadow.blurAlphaOnly() );
1019  mShadowOpacityWidget->setOpacity( shadow.opacity() );
1020  mShadowScaleSpnBx->setValue( shadow.scale() );
1021 
1022  mShadowColorBtn->setColor( shadow.color() );
1023  mShadowBlendCmbBx->setBlendMode( shadow.blendMode() );
1024 
1025  mPreviewBackgroundBtn->setColor( format.previewBackgroundColor() );
1026  mPreviewBackgroundBtn->setDefaultColor( format.previewBackgroundColor() );
1028 
1030 }
1031 
1033 {
1034  QgsSettings settings;
1035  settings.setValue( QStringLiteral( "Windows/Labeling/FontPreviewSplitState" ), mFontPreviewSplitter->saveState() );
1036  settings.setValue( QStringLiteral( "Windows/Labeling/OptionsSplitState" ), mLabelingOptionsSplitter->saveState() );
1037 
1038  int prevIndex = mLabelingOptionsListWidget->currentRow();
1039  if ( mWidgetMode == Text )
1040  {
1041  switch ( prevIndex )
1042  {
1043  case 3: // background - account for removed mask tab
1044  case 4: // shadow - account for removed mask tab
1045  prevIndex++;
1046  break;
1047  }
1048  }
1049 
1050  settings.setValue( QStringLiteral( "Windows/Labeling/Tab" ), prevIndex );
1051 }
1052 
1053 QgsTextFormat QgsTextFormatWidget::format( bool includeDataDefinedProperties ) const
1054 {
1056  format.setColor( btnTextColor->color() );
1057  format.setFont( mRefFont );
1058  format.setSize( mFontSizeSpinBox->value() );
1059  format.setNamedStyle( mFontStyleComboBox->currentText() );
1060  format.setOpacity( mTextOpacityWidget->opacity() );
1061  format.setStretchFactor( mSpinStretch->value() );
1062  format.setBlendMode( comboBlendMode->blendMode() );
1063  format.setSizeUnit( mFontSizeUnitWidget->unit() );
1064  format.setSizeMapUnitScale( mFontSizeUnitWidget->getMapUnitScale() );
1065  format.setLineHeight( mFontLineHeightSpinBox->value() );
1066  format.setPreviewBackgroundColor( mPreviewBackgroundColor );
1067  format.setOrientation( static_cast< QgsTextFormat::TextOrientation >( mTextOrientationComboBox->currentData().toInt() ) );
1068  format.setAllowHtmlFormatting( mHtmlFormattingCheckBox->isChecked( ) );
1069  format.setCapitalization( static_cast< Qgis::Capitalization >( mFontCapitalsComboBox->currentData().toInt() ) );
1070 
1071  // buffer
1072  QgsTextBufferSettings buffer;
1073  buffer.setEnabled( mBufferDrawChkBx->isChecked() );
1074  buffer.setSize( spinBufferSize->value() );
1075  buffer.setColor( btnBufferColor->color() );
1076  buffer.setOpacity( mBufferOpacityWidget->opacity() );
1077  buffer.setSizeUnit( mBufferUnitWidget->unit() );
1078  buffer.setSizeMapUnitScale( mBufferUnitWidget->getMapUnitScale() );
1079  buffer.setJoinStyle( mBufferJoinStyleComboBox->penJoinStyle() );
1080  buffer.setFillBufferInterior( mBufferTranspFillChbx->isChecked() );
1081  buffer.setBlendMode( comboBufferBlendMode->blendMode() );
1082  if ( mBufferEffect && ( !QgsPaintEffectRegistry::isDefaultStack( mBufferEffect.get() ) || mBufferEffect->enabled() ) )
1083  buffer.setPaintEffect( mBufferEffect->clone() );
1084  else
1085  buffer.setPaintEffect( nullptr );
1086  format.setBuffer( buffer );
1087 
1088  // mask
1089  QgsTextMaskSettings mask;
1090  mask.setEnabled( mEnableMaskChkBx->isChecked() );
1091  mask.setSize( mMaskBufferSizeSpinBox->value() );
1092  mask.setOpacity( mMaskOpacityWidget->opacity() );
1093  mask.setSizeUnit( mMaskBufferUnitWidget->unit() );
1094  mask.setSizeMapUnitScale( mMaskBufferUnitWidget->getMapUnitScale() );
1095  mask.setJoinStyle( mMaskJoinStyleComboBox->penJoinStyle() );
1096  if ( mMaskEffect && ( !QgsPaintEffectRegistry::isDefaultStack( mMaskEffect.get() ) || mMaskEffect->enabled() ) )
1097  mask.setPaintEffect( mMaskEffect->clone() );
1098  else
1099  mask.setPaintEffect( nullptr );
1101  format.setMask( mask );
1102 
1103  // shape background
1104  QgsTextBackgroundSettings background;
1105  background.setEnabled( mShapeDrawChkBx->isChecked() );
1106  background.setType( static_cast< QgsTextBackgroundSettings::ShapeType >( mShapeTypeCmbBx->currentData().toInt() ) );
1107  background.setSvgFile( mShapeSVGPathLineEdit->text() );
1108  background.setSizeType( static_cast< QgsTextBackgroundSettings::SizeType >( mShapeSizeCmbBx->currentIndex() ) );
1109  background.setSize( QSizeF( mShapeSizeXSpnBx->value(), mShapeSizeYSpnBx->value() ) );
1110  background.setSizeUnit( mShapeSizeUnitWidget->unit() );
1111  background.setSizeMapUnitScale( mShapeSizeUnitWidget->getMapUnitScale() );
1112  background.setRotationType( static_cast< QgsTextBackgroundSettings::RotationType >( mShapeRotationCmbBx->currentIndex() ) );
1113  background.setRotation( mShapeRotationDblSpnBx->value() );
1114  background.setOffset( QPointF( mShapeOffsetXSpnBx->value(), mShapeOffsetYSpnBx->value() ) );
1115  background.setOffsetUnit( mShapeOffsetUnitWidget->unit() );
1116  background.setOffsetMapUnitScale( mShapeOffsetUnitWidget->getMapUnitScale() );
1117  background.setRadii( QSizeF( mShapeRadiusXDbSpnBx->value(), mShapeRadiusYDbSpnBx->value() ) );
1118  background.setRadiiUnit( mShapeRadiusUnitWidget->unit() );
1119  background.setRadiiMapUnitScale( mShapeRadiusUnitWidget->getMapUnitScale() );
1120 
1121  background.setFillColor( mShapeFillColorBtn->color() );
1122  background.setStrokeColor( mShapeStrokeColorBtn->color() );
1123  background.setStrokeWidth( mShapeStrokeWidthSpnBx->value() );
1124  background.setStrokeWidthUnit( mShapeStrokeWidthUnitWidget->unit() );
1125  background.setStrokeWidthMapUnitScale( mShapeStrokeWidthUnitWidget->getMapUnitScale() );
1126  background.setOpacity( mBackgroundOpacityWidget->opacity() );
1127  background.setBlendMode( mShapeBlendCmbBx->blendMode() );
1128  if ( mBackgroundEffect && ( !QgsPaintEffectRegistry::isDefaultStack( mBackgroundEffect.get() ) || mBackgroundEffect->enabled() ) )
1129  background.setPaintEffect( mBackgroundEffect->clone() );
1130  else
1131  background.setPaintEffect( nullptr );
1132  background.setMarkerSymbol( mBackgroundMarkerSymbolButton->clonedSymbol< QgsMarkerSymbol >() );
1133  background.setFillSymbol( mBackgroundFillSymbolButton->clonedSymbol< QgsFillSymbol >() );
1134  format.setBackground( background );
1135 
1136  // drop shadow
1137  QgsTextShadowSettings shadow;
1138  shadow.setEnabled( mShadowDrawChkBx->isChecked() );
1139  shadow.setShadowPlacement( static_cast< QgsTextShadowSettings::ShadowPlacement >( mShadowUnderCmbBx->currentData().toInt() ) );
1140  shadow.setOffsetAngle( mShadowOffsetAngleSpnBx->value() );
1141  shadow.setOffsetDistance( mShadowOffsetSpnBx->value() );
1142  shadow.setOffsetUnit( mShadowOffsetUnitWidget->unit() );
1143  shadow.setOffsetMapUnitScale( mShadowOffsetUnitWidget->getMapUnitScale() );
1144  shadow.setOffsetGlobal( mShadowOffsetGlobalChkBx->isChecked() );
1145  shadow.setBlurRadius( mShadowRadiusDblSpnBx->value() );
1146  shadow.setBlurRadiusUnit( mShadowRadiusUnitWidget->unit() );
1147  shadow.setBlurRadiusMapUnitScale( mShadowRadiusUnitWidget->getMapUnitScale() );
1148  shadow.setBlurAlphaOnly( mShadowRadiusAlphaChkBx->isChecked() );
1149  shadow.setOpacity( mShadowOpacityWidget->opacity() );
1150  shadow.setScale( mShadowScaleSpnBx->value() );
1151  shadow.setColor( mShadowColorBtn->color() );
1152  shadow.setBlendMode( mShadowBlendCmbBx->blendMode() );
1153  format.setShadow( shadow );
1154 
1155  if ( includeDataDefinedProperties )
1157 
1158  return format;
1159 }
1160 
1162 {
1163  if ( mWidgetMode != Labeling )
1164  {
1165  // we need to combine any data defined properties from the text format with existing ones from the label settings
1166  const QgsPropertyCollection formatProps = format.dataDefinedProperties();
1167  for ( const int key : formatProps.propertyKeys() )
1168  {
1169  if ( formatProps.isActive( key ) )
1170  {
1171  mDataDefinedProperties.setProperty( key, formatProps.property( key ) );
1172  }
1173  }
1174  }
1175 
1177 }
1178 
1180 {
1181  return mContext;
1182 }
1183 
1185 {
1186  if ( mButtons.contains( key ) )
1187  {
1188  QgsPropertyOverrideButton *button = mButtons[ key ];
1189  button->updateFieldLists();
1190  button->setToProperty( QgsProperty() );
1192  }
1193 }
1194 
1195 void QgsTextFormatWidget::optionsStackedWidget_CurrentChanged( int indx )
1196 {
1197  mLabelingOptionsListWidget->blockSignals( true );
1198  mLabelingOptionsListWidget->setCurrentRow( indx );
1199  mLabelingOptionsListWidget->blockSignals( false );
1200 }
1201 
1203 {
1204  mContext = context;
1205 
1206  if ( auto *lExpressionContext = mContext.expressionContext() )
1207  {
1208  mPreviewExpressionContext = *lExpressionContext;
1209  if ( mLayer )
1210  mPreviewExpressionContext.appendScope( QgsExpressionContextUtils::layerScope( mLayer ) );
1211  }
1212 
1213  const auto symbolButtonWidgets = findChildren<QgsSymbolButton *>();
1214  for ( QgsSymbolButton *symbolWidget : symbolButtonWidgets )
1215  {
1216  symbolWidget->setMapCanvas( mContext.mapCanvas() );
1217  symbolWidget->setMessageBar( mContext.messageBar() );
1218  }
1219 }
1220 
1221 void QgsTextFormatWidget::collapseSample( bool collapse )
1222 {
1223  if ( collapse )
1224  {
1225  QList<int> splitSizes = mFontPreviewSplitter->sizes();
1226  if ( splitSizes[0] > groupBox_mPreview->height() )
1227  {
1228  const int delta = splitSizes[0] - groupBox_mPreview->height();
1229  splitSizes[0] -= delta;
1230  splitSizes[1] += delta;
1231  mFontPreviewSplitter->setSizes( splitSizes );
1232  }
1233  }
1234 }
1235 
1236 void QgsTextFormatWidget::changeTextColor( const QColor &color )
1237 {
1238  Q_UNUSED( color )
1239  updatePreview();
1240 }
1241 
1242 void QgsTextFormatWidget::updateFont( const QFont &font )
1243 {
1244  // update background reference font
1245  if ( font != mRefFont )
1246  {
1247  mRefFont = font;
1248  }
1249 
1250  // test if font is actually available
1251  // NOTE: QgsFontUtils::fontMatchOnSystem may fail here, just crosscheck family
1252  mFontMissingLabel->setVisible( !QgsFontUtils::fontFamilyMatchOnSystem( mRefFont.family() ) );
1253 
1254  mDirectSymbLeftLineEdit->setFont( mRefFont );
1255  mDirectSymbRightLineEdit->setFont( mRefFont );
1256 
1257  blockFontChangeSignals( true );
1258  mFontFamilyCmbBx->setCurrentFont( mRefFont );
1259  populateFontStyleComboBox();
1260  mFontUnderlineBtn->setChecked( mRefFont.underline() );
1261  mFontStrikethroughBtn->setChecked( mRefFont.strikeOut() );
1262  mKerningCheckBox->setChecked( mRefFont.kerning() );
1263  blockFontChangeSignals( false );
1264 
1265  // update font name with font face
1266 // font.setPixelSize( 24 );
1267 
1268  updatePreview();
1269 }
1270 
1271 void QgsTextFormatWidget::blockFontChangeSignals( bool blk )
1272 {
1273  mFontFamilyCmbBx->blockSignals( blk );
1274  mFontStyleComboBox->blockSignals( blk );
1275  mFontCapitalsComboBox->blockSignals( blk );
1276  mFontUnderlineBtn->blockSignals( blk );
1277  mFontStrikethroughBtn->blockSignals( blk );
1278  mFontWordSpacingSpinBox->blockSignals( blk );
1279  mFontLetterSpacingSpinBox->blockSignals( blk );
1280  mKerningCheckBox->blockSignals( blk );
1281 }
1282 
1284 {
1285  // In dock mode we don't have a preview we
1286  // just let stuff know we have changed because
1287  // there might be live updates connected.
1288  if ( mDockMode )
1289  {
1290  emit widgetChanged();
1291  return;
1292  }
1293 
1294  scrollPreview();
1295  lblFontPreview->setFormat( format() );
1296 }
1297 
1298 void QgsTextFormatWidget::scrollPreview()
1299 {
1300  scrollArea_mPreview->ensureVisible( 0, 0, 0, 0 );
1301 }
1302 
1304 {
1305  mPreviewBackgroundColor = color;
1306 
1307  scrollArea_mPreview->widget()->setStyleSheet( QStringLiteral( "background: rgb(%1, %2, %3);" ).arg( QString::number( color.red() ),
1308  QString::number( color.green() ),
1309  QString::number( color.blue() ) ) );
1310 }
1311 
1312 void QgsTextFormatWidget::changeBufferColor( const QColor &color )
1313 {
1314  Q_UNUSED( color )
1315  updatePreview();
1316 }
1317 
1319 {
1320  const QgsWkbTypes::GeometryType currentGeometryType = labelGeometryType();
1321  bool showLineFrame = false;
1322  bool showCentroidFrame = false;
1323  bool showQuadrantFrame = false;
1324  bool showFixedQuadrantFrame = false;
1325  bool showPlacementPriorityFrame = false;
1326  bool showOffsetTypeFrame = false;
1327  bool showOffsetFrame = false;
1328  bool showDistanceFrame = false;
1329  bool showRotationFrame = false;
1330  bool showMaxCharAngleFrame = false;
1331 
1332  const Qgis::LabelPlacement currentPlacement = static_cast< Qgis::LabelPlacement >( mPlacementModeComboBox->currentData().toInt() );
1333  const bool showPolygonPlacementOptions = ( currentGeometryType == QgsWkbTypes::PolygonGeometry && currentPlacement != Qgis::LabelPlacement::Line && currentPlacement != Qgis::LabelPlacement::PerimeterCurved && currentPlacement != Qgis::LabelPlacement::OutsidePolygons );
1334 
1335  bool enableMultiLinesFrame = true;
1336 
1337  if ( currentPlacement == Qgis::LabelPlacement::AroundPoint
1338  && ( currentGeometryType == QgsWkbTypes::PointGeometry || currentGeometryType == QgsWkbTypes::PolygonGeometry ) )
1339  {
1340  showCentroidFrame = currentGeometryType == QgsWkbTypes::PolygonGeometry;
1341  showDistanceFrame = true;
1342  //showRotationFrame = true; // TODO: uncomment when supported
1343  showQuadrantFrame = currentGeometryType == QgsWkbTypes::PointGeometry;
1344  }
1345  else if ( currentPlacement == Qgis::LabelPlacement::OverPoint
1346  && ( currentGeometryType == QgsWkbTypes::PointGeometry || currentGeometryType == QgsWkbTypes::PolygonGeometry ) )
1347  {
1348  showCentroidFrame = currentGeometryType == QgsWkbTypes::PolygonGeometry;
1349  showQuadrantFrame = true;
1350  showFixedQuadrantFrame = true;
1351  showOffsetFrame = true;
1352  showRotationFrame = true;
1353  }
1354  else if ( currentGeometryType == QgsWkbTypes::PointGeometry && currentPlacement == Qgis::LabelPlacement::OrderedPositionsAroundPoint )
1355  {
1356  showDistanceFrame = true;
1357  showPlacementPriorityFrame = true;
1358  showOffsetTypeFrame = true;
1359  }
1360  else if ( ( currentGeometryType == QgsWkbTypes::LineGeometry && currentPlacement == Qgis::LabelPlacement::Line )
1361  || ( currentGeometryType == QgsWkbTypes::PolygonGeometry && currentPlacement == Qgis::LabelPlacement::Line )
1362  || ( currentGeometryType == QgsWkbTypes::LineGeometry && currentPlacement == Qgis::LabelPlacement::Curved )
1363  || ( currentGeometryType == QgsWkbTypes::PolygonGeometry && currentPlacement == Qgis::LabelPlacement::PerimeterCurved ) )
1364  {
1365  showLineFrame = true;
1366  showDistanceFrame = true;
1367  //showRotationFrame = true; // TODO: uncomment when supported
1368 
1369  const bool offline = chkLineAbove->isChecked() || chkLineBelow->isChecked();
1370  chkLineOrientationDependent->setEnabled( offline );
1371  mPlacementDistanceFrame->setEnabled( offline );
1372 
1373  const bool isCurved = ( currentGeometryType == QgsWkbTypes::LineGeometry && currentPlacement == Qgis::LabelPlacement::Curved )
1374  || ( currentGeometryType == QgsWkbTypes::PolygonGeometry && currentPlacement == Qgis::LabelPlacement::PerimeterCurved );
1375  showMaxCharAngleFrame = isCurved;
1376  // TODO: enable mMultiLinesFrame when supported for curved labels
1377  enableMultiLinesFrame = !isCurved;
1378  }
1379  else if ( currentGeometryType == QgsWkbTypes::PolygonGeometry
1380  && ( currentPlacement == Qgis::LabelPlacement::OutsidePolygons || mCheckAllowLabelsOutsidePolygons->isChecked() || mAllowOutsidePolygonsDDBtn->isActive() ) )
1381  {
1382  showDistanceFrame = true;
1383  }
1384 
1385  mPlacementLineFrame->setVisible( showLineFrame );
1386  mPlacementPolygonFrame->setVisible( showPolygonPlacementOptions );
1387  mPlacementCentroidFrame->setVisible( showCentroidFrame );
1388  mPlacementQuadrantFrame->setVisible( showQuadrantFrame );
1389  mPlacementFixedQuadrantFrame->setVisible( showFixedQuadrantFrame );
1390  mPlacementCartographicFrame->setVisible( showPlacementPriorityFrame );
1391  mPlacementOffsetFrame->setVisible( showOffsetFrame );
1392  mPlacementDistanceFrame->setVisible( showDistanceFrame );
1393  mPlacementOffsetTypeFrame->setVisible( showOffsetTypeFrame );
1394  mPlacementRotationFrame->setVisible( showRotationFrame );
1395  mPlacementRepeatGroupBox->setVisible( currentGeometryType == QgsWkbTypes::LineGeometry || ( currentGeometryType == QgsWkbTypes::PolygonGeometry &&
1396  ( currentPlacement == Qgis::LabelPlacement::Line || currentPlacement == Qgis::LabelPlacement::PerimeterCurved ) ) );
1397  mPlacementOverrunGroupBox->setVisible( currentGeometryType == QgsWkbTypes::LineGeometry && currentPlacement != Qgis::LabelPlacement::Horizontal );
1398  mLineAnchorGroupBox->setVisible( currentGeometryType == QgsWkbTypes::LineGeometry );
1399  mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame );
1400 
1401  mMultiLinesFrame->setEnabled( enableMultiLinesFrame );
1402 
1403 
1404  QString helperText;
1405  switch ( currentPlacement )
1406  {
1408  if ( currentGeometryType == QgsWkbTypes::PointGeometry )
1409  helperText = tr( "Arranges label candidates in a clockwise circle around the feature, preferring placements to the top-right of the feature." );
1410  else if ( currentGeometryType == QgsWkbTypes::PolygonGeometry )
1411  helperText = tr( "Arranges label candidates in a cluster around the feature's centroid, preferring placements directly over the centroid." );
1412  break;
1414  if ( currentGeometryType == QgsWkbTypes::PointGeometry )
1415  helperText = tr( "Arranges label candidates directly over the feature or at a preset offset from the feature." );
1416  else if ( currentGeometryType == QgsWkbTypes::PolygonGeometry )
1417  helperText = tr( "Arranges label candidates directly over the feature's centroid, or at a preset offset from the centroid." );
1418  break;
1420  if ( currentGeometryType == QgsWkbTypes::LineGeometry )
1421  helperText = tr( "Arranges label candidates parallel to a generalised line representing the feature. Placements which fall over straighter portions of the line are preferred." );
1422  else if ( currentGeometryType == QgsWkbTypes::PolygonGeometry )
1423  helperText = tr( "Arranges label candidates parallel to a generalised line representing the polygon's perimeter. Placements which fall over straighter portions of the perimeter are preferred." );
1424  break;
1426  if ( currentGeometryType == QgsWkbTypes::LineGeometry )
1427  helperText = tr( "Arranges candidates following the curvature of a line feature. Placements which fall over straighter portions of the line are preferred." );
1428  break;
1430  if ( currentGeometryType == QgsWkbTypes::PolygonGeometry )
1431  helperText = tr( "Arranges label candidates scattered throughout the polygon. Labels will always be placed horizontally, with placements further from the edges of the polygon preferred." );
1432  else if ( currentGeometryType == QgsWkbTypes::LineGeometry )
1433  helperText = tr( "Label candidates are arranged horizontally along the length of the feature." );
1434  break;
1436  if ( currentGeometryType == QgsWkbTypes::PolygonGeometry )
1437  helperText = tr( "Arranges label candidates scattered throughout the polygon. Labels are rotated to respect the polygon's orientation, with placements further from the edges of the polygon preferred." );
1438  break;
1440  if ( currentGeometryType == QgsWkbTypes::PointGeometry )
1441  helperText = tr( "Label candidates are placed in predefined positions around the features. Preference is given to positions with greatest cartographic appeal, e.g., top right and bottom right of the feature." );
1442  break;
1444  if ( currentGeometryType == QgsWkbTypes::PolygonGeometry )
1445  helperText = tr( "Arranges candidates following the curvature of the feature's perimeter. Placements which fall over straighter portions of the perimeter are preferred." );
1446  break;
1448  if ( currentGeometryType == QgsWkbTypes::PolygonGeometry )
1449  helperText = tr( "Label candidates are placed outside of the features, preferring placements which give greatest visual association between the label and the feature." );
1450  break;
1451  }
1452  mPlacementModeDescriptionLabel->setText( QStringLiteral( "<i>%1</i>" ).arg( helperText ) );
1453 }
1454 
1455 void QgsTextFormatWidget::populateFontCapitalsComboBox()
1456 {
1457  mFontCapitalsComboBox->addItem( tr( "No Change" ), static_cast< int >( Qgis::Capitalization::MixedCase ) );
1458  mFontCapitalsComboBox->addItem( tr( "All Uppercase" ), static_cast< int >( Qgis::Capitalization::AllUppercase ) );
1459  mFontCapitalsComboBox->addItem( tr( "All Lowercase" ), static_cast< int >( Qgis::Capitalization::AllLowercase ) );
1460 #if defined(HAS_KDE_QT5_SMALL_CAPS_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
1461  // Requires new enough build due to
1462  // https://bugreports.qt.io/browse/QTBUG-13965
1463  mFontCapitalsComboBox->addItem( tr( "Small Caps" ), static_cast< int >( Qgis::Capitalization::SmallCaps ) );
1464  mFontCapitalsComboBox->addItem( tr( "All Small Caps" ), static_cast< int >( Qgis::Capitalization::AllSmallCaps ) );
1465 #endif
1466  mFontCapitalsComboBox->addItem( tr( "Title Case" ), static_cast< int >( Qgis::Capitalization::TitleCase ) );
1467  mFontCapitalsComboBox->addItem( tr( "Force First Letter to Capital" ), static_cast< int >( Qgis::Capitalization::ForceFirstLetterToCapital ) );
1468 }
1469 
1470 void QgsTextFormatWidget::populateFontStyleComboBox()
1471 {
1472  mFontStyleComboBox->clear();
1473  const QStringList styles = mFontDB.styles( mRefFont.family() );
1474  const auto constStyles = styles;
1475  for ( const QString &style : constStyles )
1476  {
1477  mFontStyleComboBox->addItem( style );
1478  }
1479 
1480  QString targetStyle = mFontDB.styleString( mRefFont );
1481  if ( !styles.contains( targetStyle ) )
1482  {
1483  const QFont f = QFont( mRefFont.family() );
1484  targetStyle = QFontInfo( f ).styleName();
1485  mRefFont.setStyleName( targetStyle );
1486  }
1487  int curIndx = 0;
1488  const int stylIndx = mFontStyleComboBox->findText( targetStyle );
1489  if ( stylIndx > -1 )
1490  {
1491  curIndx = stylIndx;
1492  }
1493 
1494  mFontStyleComboBox->setCurrentIndex( curIndx );
1495 }
1496 
1497 void QgsTextFormatWidget::mFontSizeSpinBox_valueChanged( double d )
1498 {
1499  mRefFont.setPointSizeF( d );
1500  updateFont( mRefFont );
1501 }
1502 
1503 void QgsTextFormatWidget::mFontFamilyCmbBx_currentFontChanged( const QFont &f )
1504 {
1505  mRefFont.setFamily( f.family() );
1506  updateFont( mRefFont );
1507 }
1508 
1509 void QgsTextFormatWidget::mFontStyleComboBox_currentIndexChanged( const QString &text )
1510 {
1511  QgsFontUtils::updateFontViaStyle( mRefFont, text );
1512  updateFont( mRefFont );
1513 }
1514 
1515 void QgsTextFormatWidget::mFontUnderlineBtn_toggled( bool ckd )
1516 {
1517  mRefFont.setUnderline( ckd );
1518  updateFont( mRefFont );
1519 }
1520 
1521 void QgsTextFormatWidget::mFontStrikethroughBtn_toggled( bool ckd )
1522 {
1523  mRefFont.setStrikeOut( ckd );
1524  updateFont( mRefFont );
1525 }
1526 
1527 void QgsTextFormatWidget::kerningToggled( bool checked )
1528 {
1529  mRefFont.setKerning( checked );
1530  updateFont( mRefFont );
1531 }
1532 
1533 void QgsTextFormatWidget::mFontWordSpacingSpinBox_valueChanged( double spacing )
1534 {
1535  mRefFont.setWordSpacing( spacing );
1536  updateFont( mRefFont );
1537 }
1538 
1539 void QgsTextFormatWidget::mFontLetterSpacingSpinBox_valueChanged( double spacing )
1540 {
1541  mRefFont.setLetterSpacing( QFont::AbsoluteSpacing, spacing );
1542  updateFont( mRefFont );
1543 }
1544 
1545 void QgsTextFormatWidget::mFontSizeUnitWidget_changed()
1546 {
1547  // disable pixel size limiting for labels defined in points
1548  if ( mFontSizeUnitWidget->unit() != QgsUnitTypes::RenderMapUnits )
1549  {
1550  mFontLimitPixelChkBox->setChecked( false );
1551  }
1552  else if ( mMinPixelLimit == 0 )
1553  {
1554  // initial minimum trigger value set, turn on pixel size limiting by default
1555  // for labels defined in map units (ignored after first settings save)
1556  mFontLimitPixelChkBox->setChecked( true );
1557  }
1558  updateFont( mRefFont );
1559 }
1560 
1561 void QgsTextFormatWidget::mFontMinPixelSpinBox_valueChanged( int px )
1562 {
1563  // ensure max font pixel size for map unit labels can't be lower than min
1564  mFontMaxPixelSpinBox->setMinimum( px );
1565  mFontMaxPixelSpinBox->update();
1566 }
1567 
1568 void QgsTextFormatWidget::mFontMaxPixelSpinBox_valueChanged( int px )
1569 {
1570  // ensure max font pixel size for map unit labels can't be lower than min
1571  if ( px < mFontMinPixelSpinBox->value() )
1572  {
1573  mFontMaxPixelSpinBox->blockSignals( true );
1574  mFontMaxPixelSpinBox->setValue( mFontMinPixelSpinBox->value() );
1575  mFontMaxPixelSpinBox->blockSignals( false );
1576  }
1577  mFontMaxPixelSpinBox->setMinimum( mFontMinPixelSpinBox->value() );
1578 }
1579 
1580 void QgsTextFormatWidget::mBufferUnitWidget_changed()
1581 {
1582  updateFont( mRefFont );
1583 }
1584 
1585 void QgsTextFormatWidget::mMaskBufferUnitWidget_changed()
1586 {
1587  updateFont( mRefFont );
1588 }
1589 
1590 void QgsTextFormatWidget::mCoordXDDBtn_changed()
1591 {
1592  updateDataDefinedAlignment();
1593 }
1594 
1595 void QgsTextFormatWidget::mCoordXDDBtn_activated( bool isActive )
1596 {
1597  if ( !isActive )
1598  return;
1599 
1600  mCoordPointDDBtn->setActive( false );
1601 }
1602 
1603 void QgsTextFormatWidget::mCoordYDDBtn_changed()
1604 {
1605  updateDataDefinedAlignment();
1606 }
1607 
1608 void QgsTextFormatWidget::mCoordYDDBtn_activated( bool isActive )
1609 {
1610  if ( !isActive )
1611  return;
1612 
1613  mCoordPointDDBtn->setActive( false );
1614 }
1615 
1616 void QgsTextFormatWidget::mCoordPointDDBtn_changed()
1617 {
1618  updateDataDefinedAlignment();
1619 }
1620 
1621 void QgsTextFormatWidget::mCoordPointDDBtn_activated( bool isActive )
1622 {
1623  if ( !isActive )
1624  return;
1625 
1626  mCoordXDDBtn->setActive( false );
1627  mCoordYDDBtn->setActive( false );
1628 }
1629 
1630 void QgsTextFormatWidget::mShapeTypeCmbBx_currentIndexChanged( int )
1631 {
1632  // shape background
1633  const QgsTextBackgroundSettings::ShapeType type = static_cast< QgsTextBackgroundSettings::ShapeType >( mShapeTypeCmbBx->currentData().toInt() );
1635  const bool isSVG = type == QgsTextBackgroundSettings::ShapeSVG;
1636  const bool isMarker = type == QgsTextBackgroundSettings::ShapeMarkerSymbol;
1637 
1638  showBackgroundRadius( isRect );
1639 
1640  mShapeSVGPathFrame->setVisible( isSVG );
1641  mBackgroundMarkerSymbolButton->setVisible( isMarker );
1642  mBackgroundFillSymbolButton->setVisible( !isSVG && !isMarker );
1643 
1644  // symbology SVG and marker renderers only support size^2 scaling,
1645  // so we only use the x size spinbox
1646  mShapeSizeYLabel->setVisible( !isSVG && !isMarker );
1647  mShapeSizeYSpnBx->setVisible( !isSVG && !isMarker );
1648  mShapeSizeYDDBtn->setVisible( !isSVG && !isMarker );
1649  mShapeSizeXLabel->setText( tr( "Size%1" ).arg( !isSVG && !isMarker ? tr( " X" ) : QString() ) );
1650 
1651  // SVG parameter setting doesn't support color's alpha component yet
1652  mShapeFillColorBtn->setAllowOpacity( !isSVG );
1653  mShapeFillColorBtn->setButtonBackground();
1654  mShapeStrokeColorBtn->setAllowOpacity( !isSVG );
1655  mShapeStrokeColorBtn->setButtonBackground();
1656 
1657  // Hide parameter widgets not used by marker symbol
1658  mShapeFillColorLabel->setVisible( isSVG );
1659  mShapeFillColorLabel->setEnabled( isSVG );
1660  mShapeFillColorBtn->setVisible( isSVG );
1661  mShapeFillColorBtn->setEnabled( isSVG );
1662  mShapeFillColorDDBtn->setVisible( isSVG );
1663  mShapeFillColorDDBtn->setEnabled( isSVG );
1664  mShapeStrokeColorLabel->setVisible( isSVG );
1665  mShapeStrokeColorLabel->setEnabled( isSVG );
1666  mShapeStrokeColorBtn->setVisible( isSVG );
1667  mShapeStrokeColorBtn->setEnabled( isSVG );
1668  mShapeStrokeColorDDBtn->setVisible( isSVG );
1669  mShapeStrokeColorDDBtn->setEnabled( isSVG );
1670  mShapeStrokeWidthLabel->setVisible( isSVG );
1671  mShapeStrokeWidthLabel->setEnabled( isSVG );
1672  mShapeStrokeWidthSpnBx->setVisible( isSVG );
1673  mShapeStrokeWidthSpnBx->setEnabled( isSVG );
1674  mShapeStrokeWidthDDBtn->setVisible( isSVG );
1675  mShapeStrokeWidthDDBtn->setEnabled( isSVG );
1676 
1677  // configure SVG parameter widgets
1678  mShapeSVGParamsBtn->setVisible( isSVG );
1679  if ( isSVG )
1680  {
1681  updateSvgWidgets( mShapeSVGPathLineEdit->text() );
1682  }
1683  // TODO: fix overriding SVG symbol's stroke width units in QgsSvgCache
1684  // currently broken, fall back to symbol units only
1685  mShapeSVGUnitsLabel->setVisible( isSVG );
1686  mShapeStrokeWidthUnitWidget->setVisible( false );
1687  mShapeStrokeUnitsDDBtn->setVisible( false );
1688  mShapeStrokeUnitsDDBtn->setEnabled( false );
1689 
1690  updateAvailableShadowPositions();
1691 }
1692 
1693 void QgsTextFormatWidget::mShapeSVGPathLineEdit_textChanged( const QString &text )
1694 {
1695  updateSvgWidgets( text );
1696 }
1697 
1699 {
1700  const int numOptionsChecked = ( chkLineAbove->isChecked() ? 1 : 0 ) +
1701  ( chkLineBelow->isChecked() ? 1 : 0 ) +
1702  ( chkLineOn->isChecked() ? 1 : 0 );
1703 
1704  if ( numOptionsChecked == 1 )
1705  {
1706  //prevent unchecking last option
1707  chkLineAbove->setEnabled( !chkLineAbove->isChecked() );
1708  chkLineBelow->setEnabled( !chkLineBelow->isChecked() );
1709  chkLineOn->setEnabled( !chkLineOn->isChecked() );
1710  }
1711  else
1712  {
1713  chkLineAbove->setEnabled( true );
1714  chkLineBelow->setEnabled( true );
1715  chkLineOn->setEnabled( true );
1716  }
1717 }
1718 
1719 void QgsTextFormatWidget::onSubstitutionsChanged( const QgsStringReplacementCollection &substitutions )
1720 {
1721  mSubstitutions = substitutions;
1722  emit widgetChanged();
1723 }
1724 
1725 void QgsTextFormatWidget::previewScaleChanged( double scale )
1726 {
1727  lblFontPreview->setScale( scale );
1728 }
1729 
1730 void QgsTextFormatWidget::updateSvgWidgets( const QString &svgPath )
1731 {
1732  if ( mShapeSVGPathLineEdit->text() != svgPath )
1733  {
1734  mShapeSVGPathLineEdit->setText( svgPath );
1735  }
1736 
1737  QString resolvedPath;
1738  bool validSVG = true;
1739  if ( ! svgPath.startsWith( QLatin1String( "base64:" ), Qt::CaseInsensitive ) )
1740  {
1741  resolvedPath = QgsSymbolLayerUtils::svgSymbolNameToPath( svgPath, QgsProject::instance()->pathResolver() );
1742  validSVG = QFileInfo::exists( resolvedPath );
1743  }
1744  else
1745  {
1746  resolvedPath = svgPath;
1747  validSVG = true;
1748  }
1749 
1750  // draw red text for path field if invalid (path can't be resolved)
1751  mShapeSVGPathLineEdit->setStyleSheet( !validSVG ? QStringLiteral( "QLineEdit{ color: rgb(225, 0, 0); }" ) : QString() );
1752  mShapeSVGPathLineEdit->setToolTip( !validSVG ? tr( "File not found" ) : resolvedPath );
1753 
1754  QColor fill, stroke;
1755  double strokeWidth = 0.0;
1756  bool fillParam = false, strokeParam = false, strokeWidthParam = false;
1757  if ( validSVG )
1758  {
1759  QgsApplication::svgCache()->containsParams( resolvedPath, fillParam, fill, strokeParam, stroke, strokeWidthParam, strokeWidth );
1760  }
1761 
1762  mShapeSVGParamsBtn->setEnabled( validSVG && ( fillParam || strokeParam || strokeWidthParam ) );
1763 
1764  mShapeFillColorLabel->setEnabled( validSVG && fillParam );
1765  mShapeFillColorBtn->setEnabled( validSVG && fillParam );
1766  mShapeFillColorDDBtn->setEnabled( validSVG && fillParam );
1767  if ( mLoadSvgParams && validSVG && fillParam )
1768  mShapeFillColorBtn->setColor( fill );
1769 
1770  mShapeStrokeColorLabel->setEnabled( validSVG && strokeParam );
1771  mShapeStrokeColorBtn->setEnabled( validSVG && strokeParam );
1772  mShapeStrokeColorDDBtn->setEnabled( validSVG && strokeParam );
1773  if ( mLoadSvgParams && validSVG && strokeParam )
1774  mShapeStrokeColorBtn->setColor( stroke );
1775 
1776  mShapeStrokeWidthLabel->setEnabled( validSVG && strokeWidthParam );
1777  mShapeStrokeWidthSpnBx->setEnabled( validSVG && strokeWidthParam );
1778  mShapeStrokeWidthDDBtn->setEnabled( validSVG && strokeWidthParam );
1779  if ( mLoadSvgParams && validSVG && strokeWidthParam )
1780  mShapeStrokeWidthSpnBx->setValue( strokeWidth );
1781 
1782  // TODO: fix overriding SVG symbol's stroke width units in QgsSvgCache
1783  // currently broken, fall back to symbol's
1784  //mShapeStrokeWidthUnitWidget->setEnabled( validSVG && strokeWidthParam );
1785  //mShapeStrokeUnitsDDBtn->setEnabled( validSVG && strokeWidthParam );
1786  mShapeSVGUnitsLabel->setEnabled( validSVG && strokeWidthParam );
1787 }
1788 
1789 void QgsTextFormatWidget::updateAvailableShadowPositions()
1790 {
1791  if ( mShadowUnderCmbBx->count() == 0
1792  || ( mShadowUnderCmbBx->findData( QgsTextShadowSettings::ShadowShape ) > -1 && mShapeTypeCmbBx->currentData().toInt() == QgsTextBackgroundSettings::ShapeMarkerSymbol )
1793  || ( mShadowUnderCmbBx->findData( QgsTextShadowSettings::ShadowShape ) == -1 && mShapeTypeCmbBx->currentData().toInt() != QgsTextBackgroundSettings::ShapeMarkerSymbol ) )
1794  {
1795  // showing invalid choices, have to rebuild the list
1796  const QgsTextShadowSettings::ShadowPlacement currentPlacement = static_cast< QgsTextShadowSettings::ShadowPlacement >( mShadowUnderCmbBx->currentData().toInt() );
1797  mShadowUnderCmbBx->clear();
1798 
1799  mShadowUnderCmbBx->addItem( tr( "Lowest Label Component" ), QgsTextShadowSettings::ShadowLowest );
1800  mShadowUnderCmbBx->addItem( tr( "Text" ), QgsTextShadowSettings::ShadowText );
1801  mShadowUnderCmbBx->addItem( tr( "Buffer" ), QgsTextShadowSettings::ShadowBuffer );
1802  if ( mShapeTypeCmbBx->currentData().toInt() != QgsTextBackgroundSettings::ShapeMarkerSymbol )
1803  mShadowUnderCmbBx->addItem( tr( "Background" ), QgsTextShadowSettings::ShadowShape ); // not supported for marker symbol background shapes
1804 
1805  mShadowUnderCmbBx->setCurrentIndex( mShadowUnderCmbBx->findData( currentPlacement ) );
1806  if ( mShadowUnderCmbBx->currentIndex() == -1 )
1807  mShadowUnderCmbBx->setCurrentIndex( 0 );
1808  }
1809 }
1810 
1811 void QgsTextFormatWidget::updateProperty()
1812 {
1813  QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
1814  const QgsPalLayerSettings::Property key = static_cast< QgsPalLayerSettings::Property >( button->propertyKey() );
1815  mDataDefinedProperties.setProperty( key, button->toProperty() );
1816  updatePreview();
1817 }
1818 
1819 void QgsTextFormatWidget::createAuxiliaryField()
1820 {
1821  if ( !mLayer )
1822  return;
1823 
1824  // try to create an auxiliary layer if not yet created
1825  if ( !mLayer->auxiliaryLayer() )
1826  {
1827  QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
1828  dlg.exec();
1829  }
1830 
1831  // return if still not exists
1832  if ( !mLayer->auxiliaryLayer() )
1833  return;
1834 
1835  QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
1836  const QgsPalLayerSettings::Property key = static_cast< QgsPalLayerSettings::Property >( button->propertyKey() );
1838 
1839  // create property in auxiliary storage if necessary
1840  if ( !mLayer->auxiliaryLayer()->exists( def ) )
1842 
1843  // update property with join field name from auxiliary storage
1844  QgsProperty property = button->toProperty();
1845  property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
1846  property.setActive( true );
1847  button->updateFieldLists();
1848  button->setToProperty( property );
1849  mDataDefinedProperties.setProperty( key, button->toProperty() );
1850  updatePreview();
1851  emit auxiliaryFieldCreated();
1852 }
1853 
1854 
1855 void QgsTextFormatWidget::updateShapeFrameStatus()
1856 {
1857  mShapeFrame->setEnabled( mShapeDrawDDBtn->isActive() || mShapeDrawChkBx->isChecked() );
1858 }
1859 
1860 void QgsTextFormatWidget::updateBufferFrameStatus()
1861 {
1862  mBufferFrame->setEnabled( mBufferDrawDDBtn->isActive() || mBufferDrawChkBx->isChecked() );
1863 }
1864 
1865 void QgsTextFormatWidget::updateShadowFrameStatus()
1866 {
1867  mShadowFrame->setEnabled( mShadowDrawDDBtn->isActive() || mShadowDrawChkBx->isChecked() );
1868 }
1869 
1870 void QgsTextFormatWidget::updateCalloutFrameStatus()
1871 {
1872  mCalloutFrame->setEnabled( mCalloutDrawDDBtn->isActive() || mCalloutsDrawCheckBox->isChecked() );
1873 }
1874 
1875 void QgsTextFormatWidget::updateDataDefinedAlignment()
1876 {
1877  // no data defined alignment without data defined position
1878  mCoordAlignmentFrame->setEnabled( ( mCoordXDDBtn->isActive() && mCoordYDDBtn->isActive() )
1879  || mCoordPointDDBtn->isActive() );
1880 }
1881 
1882 void QgsTextFormatWidget::overlapModeChanged()
1883 {
1884  QString description;
1885  switch ( static_cast< Qgis::LabelOverlapHandling >( mComboOverlapHandling->currentData().toInt() ) )
1886  {
1888  description = tr( "Overlapping labels will never be placed for the layer, even if it means some labels will be missing. (To see unplaced labels use the \"Show Unplaced Labels\" toolbar action.)" );
1889  break;
1891  description = tr( "If a label cannot otherwise be placed for a feature then an overlapping label is permitted." );
1892  break;
1894  description = tr( "Labels from this layer may freely overlap other labels or label obstacles without penalty." );
1895  break;
1896  }
1897 
1898  mOverlapModeDescriptionLabel->setText( QStringLiteral( "<i>%1</i>" ).arg( description ) );
1899 }
1900 
1901 void QgsTextFormatWidget::setFormatFromStyle( const QString &name, QgsStyle::StyleEntity type, const QString &stylePath )
1902 {
1903  if ( name.isEmpty() )
1904  return;
1905 
1906  QgsStyle *style = nullptr;
1907 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
1908  style = QgsProject::instance()->styleSettings()->styleAtPath( stylePath );
1909 #else
1910  ( void )stylePath;
1911 #endif
1912 
1913  if ( !style )
1914  style = QgsStyle::defaultStyle();
1915 
1916  switch ( type )
1917  {
1920  case QgsStyle::TagEntity:
1924  return;
1925 
1927  {
1928  if ( !style->textFormatNames().contains( name ) )
1929  return;
1930 
1931  const QgsTextFormat newFormat = style->textFormat( name );
1932  setFormat( newFormat );
1933  break;
1934  }
1935 
1937  {
1938  if ( !style->labelSettingsNames().contains( name ) )
1939  return;
1940 
1941  const QgsTextFormat newFormat = style->labelSettings( name ).format();
1942  setFormat( newFormat );
1943  break;
1944  }
1945  }
1946 }
1947 
1949 {
1951  saveDlg.setDefaultTags( mTextFormatsListWidget->currentTagFilter() );
1952  if ( !saveDlg.exec() )
1953  return;
1954 
1955  if ( saveDlg.name().isEmpty() )
1956  return;
1957 
1958  QgsStyle *style = saveDlg.destinationStyle();
1959  if ( !style )
1960  return;
1961 
1962  // check if there is no format with same name
1963  if ( style->textFormatNames().contains( saveDlg.name() ) )
1964  {
1965  const int res = QMessageBox::warning( this, tr( "Save Text Format" ),
1966  tr( "Format with name '%1' already exists. Overwrite?" )
1967  .arg( saveDlg.name() ),
1968  QMessageBox::Yes | QMessageBox::No );
1969  if ( res != QMessageBox::Yes )
1970  {
1971  return;
1972  }
1973  style->removeTextFormat( saveDlg.name() );
1974  }
1975 
1976  const QStringList symbolTags = saveDlg.tags().split( ',' );
1977 
1978  const QgsTextFormat newFormat = format();
1979  style->addTextFormat( saveDlg.name(), newFormat );
1980  style->saveTextFormat( saveDlg.name(), newFormat, saveDlg.isFavorite(), symbolTags );
1981 }
1982 
1983 void QgsTextFormatWidget::mShapeSVGSelectorBtn_clicked()
1984 {
1985  QgsSvgSelectorDialog svgDlg( this );
1986  svgDlg.setWindowTitle( tr( "Select SVG file" ) );
1987  svgDlg.svgSelector()->setSvgPath( mShapeSVGPathLineEdit->text().trimmed() );
1988 
1989  if ( svgDlg.exec() == QDialog::Accepted )
1990  {
1991  const QString svgPath = svgDlg.svgSelector()->currentSvgPath();
1992  if ( !svgPath.isEmpty() )
1993  {
1994  mShapeSVGPathLineEdit->setText( svgPath );
1995  updatePreview();
1996  }
1997  }
1998 }
1999 
2000 void QgsTextFormatWidget::mShapeSVGParamsBtn_clicked()
2001 {
2002  const QString svgPath = mShapeSVGPathLineEdit->text();
2003  mLoadSvgParams = true;
2004  updateSvgWidgets( svgPath );
2005  mLoadSvgParams = false;
2006 }
2007 
2008 void QgsTextFormatWidget::mShapeRotationCmbBx_currentIndexChanged( int index )
2009 {
2010  mShapeRotationDblSpnBx->setEnabled( static_cast< QgsTextBackgroundSettings::RotationType >( index ) != QgsTextBackgroundSettings::RotationSync );
2011  mShapeRotationDDBtn->setEnabled( static_cast< QgsTextBackgroundSettings::RotationType >( index ) != QgsTextBackgroundSettings::RotationSync );
2012 }
2013 
2014 void QgsTextFormatWidget::mPreviewTextEdit_textChanged( const QString &text )
2015 {
2016  lblFontPreview->setText( text );
2017  updatePreview();
2018 }
2019 
2020 void QgsTextFormatWidget::mPreviewTextBtn_clicked()
2021 {
2022  mPreviewTextEdit->setText( QStringLiteral( "Lorem Ipsum" ) );
2023  updatePreview();
2024 }
2025 
2026 void QgsTextFormatWidget::mPreviewBackgroundBtn_colorChanged( const QColor &color )
2027 {
2028  setPreviewBackground( color );
2029 }
2030 
2031 void QgsTextFormatWidget::mDirectSymbLeftToolBtn_clicked()
2032 {
2033  bool gotChar = false;
2034 
2035  const QChar initial = !mDirectSymbLeftLineEdit->text().isEmpty() ? mDirectSymbLeftLineEdit->text().at( 0 ) : QChar();
2036  const QChar dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ), initial );
2037 
2038  if ( !gotChar )
2039  return;
2040 
2041  if ( !dirSymb.isNull() )
2042  mDirectSymbLeftLineEdit->setText( QString( dirSymb ) );
2043 }
2044 
2045 void QgsTextFormatWidget::mDirectSymbRightToolBtn_clicked()
2046 {
2047  bool gotChar = false;
2048  const QChar initial = !mDirectSymbRightLineEdit->text().isEmpty() ? mDirectSymbRightLineEdit->text().at( 0 ) : QChar();
2049  const QChar dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ), initial );
2050 
2051  if ( !gotChar )
2052  return;
2053 
2054  if ( !dirSymb.isNull() )
2055  mDirectSymbRightLineEdit->setText( QString( dirSymb ) );
2056 }
2057 
2058 void QgsTextFormatWidget::chkLineOrientationDependent_toggled( bool active )
2059 {
2060  if ( active )
2061  {
2062  chkLineAbove->setText( tr( "Left of line" ) );
2063  chkLineBelow->setText( tr( "Right of line" ) );
2064  }
2065  else
2066  {
2067  chkLineAbove->setText( tr( "Above line" ) );
2068  chkLineBelow->setText( tr( "Below line" ) );
2069  }
2070 }
2071 
2072 
2073 void QgsTextFormatWidget::mToolButtonConfigureSubstitutes_clicked()
2074 {
2076  if ( panel && panel->dockMode() )
2077  {
2079  widget->setPanelTitle( tr( "Substitutions" ) );
2080  widget->setSubstitutions( mSubstitutions );
2081  connect( widget, &QgsSubstitutionListWidget::substitutionsChanged, this, &QgsTextFormatWidget::onSubstitutionsChanged );
2082  panel->openPanel( widget );
2083  return;
2084  }
2085 
2086  QgsSubstitutionListDialog dlg( this );
2087  dlg.setSubstitutions( mSubstitutions );
2088  if ( dlg.exec() == QDialog::Accepted )
2089  {
2090  mSubstitutions = dlg.substitutions();
2091  emit widgetChanged();
2092  }
2093 }
2094 
2095 void QgsTextFormatWidget::showBackgroundRadius( bool show )
2096 {
2097  mShapeRadiusLabel->setVisible( show );
2098  mShapeRadiusXDbSpnBx->setVisible( show );
2099 
2100  mShapeRadiusYDbSpnBx->setVisible( show );
2101 
2102  mShapeRadiusUnitWidget->setVisible( show );
2103 
2104  mShapeRadiusDDBtn->setVisible( show );
2105  mShapeRadiusUnitsDDBtn->setVisible( show );
2106 }
2107 
2109 {
2110  if ( auto *lExpressionContext = mContext.expressionContext() )
2111  return *lExpressionContext;
2112 
2113  QgsExpressionContext expContext;
2117  if ( mMapCanvas )
2119 
2120  if ( mLayer )
2122 
2123  //TODO - show actual value
2124  expContext.setOriginalValueVariable( QVariant() );
2126 
2127  return expContext;
2128 }
2129 
2131 {
2132  if ( mGeometryGeneratorGroupBox->isChecked() )
2133  return mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
2134  else if ( mLayer )
2135  return mLayer->geometryType();
2136  else
2137  return mGeomType;
2138 }
2139 
2140 
2141 //
2142 // QgsTextFormatDialog
2143 //
2144 
2145 QgsTextFormatDialog::QgsTextFormatDialog( const QgsTextFormat &format, QgsMapCanvas *mapCanvas, QWidget *parent, Qt::WindowFlags fl, QgsVectorLayer *layer )
2146  : QDialog( parent, fl )
2147 {
2148  setWindowTitle( tr( "Text Settings" ) );
2149 
2150  mFormatWidget = new QgsTextFormatWidget( format, mapCanvas, this, layer );
2151  mFormatWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
2152 
2153  QVBoxLayout *layout = new QVBoxLayout( this );
2154  layout->addWidget( mFormatWidget );
2155 
2156  mButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, Qt::Horizontal, this );
2157  layout->addWidget( mButtonBox );
2158 
2159  setLayout( layout );
2161 
2162  connect( mButtonBox->button( QDialogButtonBox::Ok ), &QAbstractButton::clicked, this, &QDialog::accept );
2163  connect( mButtonBox->button( QDialogButtonBox::Cancel ), &QAbstractButton::clicked, this, &QDialog::reject );
2164  connect( mButtonBox->button( QDialogButtonBox::Help ), &QAbstractButton::clicked, this, &QgsTextFormatDialog::showHelp );
2165 }
2166 
2168 {
2169  return mFormatWidget->format();
2170 }
2171 
2172 void QgsTextFormatDialog::showHelp()
2173 {
2174  QgsHelp::openHelp( QStringLiteral( "style_library/label_settings.html#formatting-the-label-text" ) );
2175 }
2176 
2178 {
2179  mFormatWidget->setContext( context );
2180 }
2181 
2182 QDialogButtonBox *QgsTextFormatDialog::buttonBox() const
2183 {
2184  return mButtonBox;
2185 }
2186 
2188  : QgsPanelWidgetWrapper( new QgsTextFormatWidget( format, mapCanvas, nullptr, layer ), parent )
2189 {
2190  mFormatWidget = qobject_cast< QgsTextFormatWidget * >( widget() );
2191  connect( mFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [ = ]
2192  {
2193  if ( !mBlockSignals )
2194  emit widgetChanged();
2195  } );
2196 }
2197 
2199 {
2200  return mFormatWidget->format();
2201 }
2202 
2204 {
2205  mBlockSignals = true;
2206  mFormatWidget->setFormat( format );
2207  mBlockSignals = false;
2208 }
2209 
2211 {
2212  mFormatWidget->setContext( context );
2213 }
2214 
2216 {
2217  mFormatWidget->setDockMode( dockMode );
2219 }
@ FromPoint
Offset distance applies from point geometry.
@ FromSymbolBounds
Offset distance applies from rendered symbol bounds.
LabelPlacement
Placement modes which determine how label candidates are generated for a feature.
Definition: qgis.h:561
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
@ Free
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
@ OrderedPositionsAroundPoint
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
@ OutsidePolygons
Candidates are placed outside of polygon boundaries. Applies to polygon layers only....
Capitalization
String capitalization options.
Definition: qgis.h:1611
@ AllSmallCaps
Force all characters to small caps (since QGIS 3.24)
@ MixedCase
Mixed case, ie no change.
@ AllLowercase
Convert all characters to lowercase.
@ TitleCase
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
@ SmallCaps
Mixed case small caps (since QGIS 3.24)
@ ForceFirstLetterToCapital
Convert just the first letter of each word to uppercase, leave the rest untouched.
@ AllUppercase
Convert all characters to uppercase.
@ Marker
Marker symbol.
@ Fill
Fill symbol.
LabelOverlapHandling
Label overlap handling.
Definition: qgis.h:546
@ AllowOverlapAtNoCost
Labels may freely overlap other labels, at no cost.
@ AllowOverlapIfRequired
Avoids overlapping labels when possible, but permit overlaps if labels for features cannot otherwise ...
@ PreventOverlap
Do not allow labels to overlap other labels.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
bool addAuxiliaryField(const QgsPropertyDefinition &definition)
Adds an auxiliary field for the given property.
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
bool exists(const QgsPropertyDefinition &definition) const
Returns true if the property is stored in the layer already, false otherwise.
A dialog for selecting a single character from a single font.
QChar selectCharacter(bool *gotChar, const QFont &font, const QString &style, QChar initialSelection=QChar())
Opens the dialog modally and returns when the user has selected a character.
A QGIS expression editor based on QScintilla2.
void collapsedStateChanged(bool collapsed)
Signal emitted when groupbox collapsed/expanded state is changed, and when first shown.
A groupbox that collapses/expands when toggled and can save its collapsed and checked states.
A cross platform button subclass for selecting colors.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
void changed()
Emitted when the paint effect properties change.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user.
static const QString EXPR_ORIGINAL_VALUE
Inbuilt variable name for value original value variable.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:30
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
static bool fontFamilyMatchOnSystem(const QString &family, QString *chosen=nullptr, bool *match=nullptr)
Check whether font family is on system.
static bool updateFontViaStyle(QFont &f, const QString &fontstyle, bool fallback=false)
Updates font with named style and retain all font properties.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition: qgsgui.cpp:180
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
static QIcon iconForWkbType(QgsWkbTypes::Type type)
Returns the icon for a vector layer whose geometry type is provided.
@ SymbolLeftRight
Place direction symbols on left/right of label.
@ SymbolAbove
Place direction symbols on above label.
@ SymbolBelow
Place direction symbols on below label.
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
double scale() const
Returns the calculated map scale.
QgsUnitTypes::DistanceUnit mapUnits() const
Returns the units of the map's geographical coordinates - used for scale calculation.
A marker symbol type, for rendering Point and MultiPoint geometries.
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
A dialog to create a new auxiliary layer.
A widget for setting an opacity value.
static QgsPaintEffect * defaultStack()
Returns a new effect stack consisting of a sensible selection of default effects.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
Property
Data definable properties.
@ MaskEnabled
Whether the mask is enabled.
@ LabelRotation
Label rotation.
@ PositionY
Y-coordinate data defined label position.
@ OverlapHandling
Overlap handling technique (since QGIS 3.26)
@ OverrunDistance
Distance which labels can extend past either end of linear features.
@ Strikeout
Use strikeout.
@ FontStyle
Font style name.
@ PositionX
X-coordinate data defined label position.
@ CalloutDraw
Show callout.
@ Underline
Use underline.
@ FontLetterSpacing
Letter spacing.
@ MaskJoinStyle
Mask join style.
@ PositionPoint
Point-coordinate data defined label position.
@ Bold
Use bold style.
@ Hali
Horizontal alignment for data defined label position (Left, Center, Right)
@ FontStretchFactor
Font stretch factor, since QGIS 3.24.
@ MaskBufferUnit
Mask buffer size unit.
@ LabelAllParts
Whether all parts of multi-part features should be labeled.
@ AllowDegradedPlacement
Allow degraded label placements (since QGIS 3.26)
@ ShadowOpacity
Shadow opacity.
@ BufferOpacity
Buffer opacity.
@ ShapeOpacity
Shape opacity.
@ FontSizeUnit
Font size units.
@ Italic
Use italic style.
@ FontWordSpacing
Word spacing.
@ MaskBufferSize
Mask buffer size.
@ MinimumScale
Minimum map scale (ie most "zoomed out")
@ FontBlendMode
Text blend mode.
@ MaximumScale
Maximum map scale (ie most "zoomed in")
@ MaskOpacity
Mask opacity.
@ Family
Font family.
@ PolygonLabelOutside
Whether labels outside a polygon feature are permitted, or should be forced (since QGIS 3....
@ FontCase
Label text case.
@ LinePlacementOptions
Line placement flags.
@ Vali
Vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top)
@ FontOpacity
Text opacity.
const QgsTextFormat & format() const
Returns the label text formatting settings, e.g., font settings, buffer settings, etc.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the labeling property definitions.
Wrapper widget for existing widgets which can't have the inheritance tree changed,...
QWidget * widget()
Returns the internal widget that is wrapped in this panel.
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
void widgetChanged()
Emitted when the widget state changes.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
bool dockMode()
Returns the dock mode state.
QgsStyle * styleAtPath(const QString &path)
Returns a reference to the style database associated with the project with matching file path.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:479
const QgsProjectStyleSettings * styleSettings() const
Returns the project's style settings, which contains settings and properties relating to how a QgsPro...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
QSet< int > propertyKeys() const override
Returns a list of property keys contained within the collection.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Definition for a property.
Definition: qgsproperty.h:47
A button for controlling property overrides which may apply to a widget.
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
void updateFieldLists()
Updates list of fields.
void changed()
Emitted when property definition changes.
void activated(bool isActive)
Emitted when the activated status of the widget changes.
void init(int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer=nullptr, bool auxiliaryStorageEnabled=false)
Initialize a newly constructed property button (useful if button was included in a UI layout).
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
int propertyKey() const
Returns the property key linked to the button.
void setToProperty(const QgsProperty &property)
Sets the widget to reflect the current state of a QgsProperty.
void createAuxiliaryField()
Emitted when creating a new auxiliary field.
A store for object properties.
Definition: qgsproperty.h:231
void setField(const QString &field)
Sets the field name the property references.
A combobox which lets the user select map scale from predefined list and highlights nearest to curren...
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
A collection of string replacements (specified using QgsStringReplacement objects).
void saveEntity()
Emitted when the user has opted to save a new entity to the style database, by clicking the "Save" bu...
void selectionChangedWithStylePath(const QString &name, QgsStyle::StyleEntity type, const QString &stylePath)
Emitted when the selected item is changed in the widget.
a dialog for setting properties of a newly saved style.
bool isFavorite() const
Returns true if the favorite is checked for the symbol.
QString name() const
Returns the entered name for the new symbol.
void setDefaultTags(const QString &tags)
Sets the default tags for the newly created item.
QString tags() const
Returns any tags entered for the new symbol (as a comma separated value list).
QgsStyle * destinationStyle()
Returns the destination style database.
QgsTextFormat textFormat(const QString &name) const
Returns the text format with the specified name.
Definition: qgsstyle.cpp:2120
QStringList textFormatNames() const
Returns a list of names of text formats in the style.
Definition: qgsstyle.cpp:2130
bool removeTextFormat(const QString &name)
Removes a text format from the style.
Definition: qgsstyle.cpp:977
StyleEntity
Enum for Entities involved in a style.
Definition: qgsstyle.h:179
@ LabelSettingsEntity
Label settings.
Definition: qgsstyle.h:185
@ TextFormatEntity
Text formats.
Definition: qgsstyle.h:184
@ SmartgroupEntity
Smart groups.
Definition: qgsstyle.h:183
@ Symbol3DEntity
3D symbol entity (since QGIS 3.14)
Definition: qgsstyle.h:187
@ SymbolEntity
Symbols.
Definition: qgsstyle.h:180
@ TagEntity
Tags.
Definition: qgsstyle.h:181
@ ColorrampEntity
Color ramps.
Definition: qgsstyle.h:182
@ LegendPatchShapeEntity
Legend patch shape (since QGIS 3.14)
Definition: qgsstyle.h:186
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
QStringList labelSettingsNames() const
Returns a list of names of label settings in the style.
Definition: qgsstyle.cpp:2194
static QgsTextFormat defaultTextFormatForProject(QgsProject *project, QgsStyle::TextFormatContext context=QgsStyle::TextFormatContext::Labeling)
Returns the default text format to use for new text based objects for the specified project,...
Definition: qgsstyle.cpp:1217
bool addTextFormat(const QString &name, const QgsTextFormat &format, bool update=false)
Adds a text format with the specified name to the style.
Definition: qgsstyle.cpp:337
QgsPalLayerSettings labelSettings(const QString &name) const
Returns the label settings with the specified name.
Definition: qgsstyle.cpp:2140
bool saveTextFormat(const QString &name, const QgsTextFormat &format, bool favorite, const QStringList &tags)
Adds a text format to the database.
Definition: qgsstyle.cpp:941
A dialog which allows users to specify a list of substitutions to apply to a string,...
A widget which allows users to specify a list of substitutions to apply to a string,...
void setSubstitutions(const QgsStringReplacementCollection &substitutions)
Sets the list of substitutions to show in the widget.
void substitutionsChanged(const QgsStringReplacementCollection &substitutions)
Emitted when the substitution definitions change.
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasStrokeParam, QColor &defaultStrokeColor, bool &hasStrokeWidthParam, double &defaultStrokeWidth, bool blocking=false) const
Tests if an SVG file contains parameters for fill, stroke color, stroke width.
A button for creating and modifying QgsSymbol settings.
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:675
Container for settings relating to a text background object.
QgsMapUnitScale strokeWidthMapUnitScale() const
Returns the map unit scale object for the shape stroke width.
void setFillSymbol(QgsFillSymbol *symbol)
Sets the current fill symbol for the background shape.
RotationType rotationType() const
Returns the method used for rotating the background shape.
QString svgFile() const
Returns the absolute path to the background SVG file, if set.
QSizeF size() const
Returns the size of the background shape.
QSizeF radii() const
Returns the radii used for rounding the corners of shapes.
QgsMapUnitScale radiiMapUnitScale() const
Returns the map unit scale object for the shape radii.
void setOpacity(double opacity)
Sets the background shape's opacity.
void setStrokeColor(const QColor &color)
Sets the color used for outlining the background shape.
QgsUnitTypes::RenderUnit strokeWidthUnit() const
Returns the units used for the shape's stroke width.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape size.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the background shape.
SizeType
Methods for determining the background shape size.
bool enabled() const
Returns whether the background is enabled.
void setRadiiUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's radii.
double opacity() const
Returns the background shape's opacity.
void setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape stroke width.
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units used for the shape's offset.
double rotation() const
Returns the rotation for the background shape, in degrees clockwise.
QColor fillColor() const
Returns the color used for filing the background shape.
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the current marker symbol for the background shape.
void setRadii(QSizeF radii)
Sets the radii used for rounding the corners of shapes.
SizeType sizeType() const
Returns the method used to determine the size of the background shape (e.g., fixed size or buffer aro...
ShapeType type() const
Returns the type of background shape (e.g., square, ellipse, SVG).
double strokeWidth() const
Returns the width of the shape's stroke (stroke).
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
ShapeType
Background shape types.
@ ShapeSquare
Square - buffered sizes only.
void setFillColor(const QColor &color)
Sets the color used for filing the background shape.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the background shape.
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's stroke width.
QColor strokeColor() const
Returns the color used for outlining the background shape.
void setRotationType(RotationType type)
Sets the method used for rotating the background shape.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape offset.
QgsFillSymbol * fillSymbol() const
Returns the fill symbol to be rendered in the background.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the background shape.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the shape size.
void setType(ShapeType type)
Sets the type of background shape to draw (e.g., square, ellipse, SVG).
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units used for the shape's size.
RotationType
Methods for determining the rotation of the background shape.
@ RotationSync
Shape rotation is synced with text rotation.
QgsUnitTypes::RenderUnit radiiUnit() const
Returns the units used for the shape's radii.
void setEnabled(bool enabled)
Sets whether the text background will be drawn.
QgsMarkerSymbol * markerSymbol() const
Returns the marker symbol to be rendered in the background.
void setRadiiMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shape radii.
void setRotation(double rotation)
Sets the rotation for the background shape, in degrees clockwise.
void setOffset(QPointF offset)
Sets the offset used for drawing the background shape.
void setSize(QSizeF size)
Sets the size of the background shape.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the shape's size.
const QgsPaintEffect * paintEffect() const
Returns the current paint effect for the background shape.
void setSvgFile(const QString &file)
Sets the path to the background SVG file.
QgsMapUnitScale offsetMapUnitScale() const
Returns the map unit scale object for the shape offset.
void setStrokeWidth(double width)
Sets the width of the shape's stroke (stroke).
QPointF offset() const
Returns the offset used for drawing the background shape.
void setOffsetUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's offset.
Container for settings relating to a text buffer.
void setFillBufferInterior(bool fill)
Sets whether the interior of the buffer will be filled in.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the buffer.
Qt::PenJoinStyle joinStyle() const
Returns the buffer join style.
double size() const
Returns the size of the buffer.
void setColor(const QColor &color)
Sets the color for the buffer.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the buffer size.
void setOpacity(double opacity)
Sets the buffer opacity.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
bool enabled() const
Returns whether the buffer is enabled.
double opacity() const
Returns the buffer opacity.
bool fillBufferInterior() const
Returns whether the interior of the buffer will be filled in.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the buffer.
const QgsPaintEffect * paintEffect() const
Returns the current paint effect for the buffer.
QColor color() const
Returns the color of the buffer.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the buffer.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the buffer.
void setSize(double size)
Sets the size of the buffer.
QgsTextFormatDialog(const QgsTextFormat &format, QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags, QgsVectorLayer *layer=nullptr)
Constructor for QgsTextFormatDialog.
QgsTextFormat format() const
Returns the current formatting settings defined by the widget.
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog's button box.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
void setFormat(const QgsTextFormat &format)
Sets the format to show in the widget.
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
QgsTextFormat format() const
Returns the current formatting settings defined by the widget.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
QgsTextFormatPanelWidget(const QgsTextFormat &format, QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr, QgsVectorLayer *layer=nullptr)
Constructor for QgsTextFormatPanelWidget.
A widget for customizing text formatting settings.
void updatePlacementWidgets()
Updates label placement options to reflect current state of widget.
QButtonGroup * mUpsidedownBtnGrp
Upside down labels button group.
QgsTextFormatWidget(const QgsTextFormat &format=QgsTextFormat(), QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr, QgsVectorLayer *layer=nullptr)
Constructor for QgsTextFormatWidget.
int mMinPixelLimit
Pixel size font limit.
void setDockMode(bool enabled)
Sets whether the widget should be shown in a compact dock mode.
QgsMapCanvas * mMapCanvas
Associated map canvas.
QgsSymbolWidgetContext context() const
Returns the context in which the widget is shown, e.g., the associated map canvas and expression cont...
void deactivateField(QgsPalLayerSettings::Property key)
Deactivate a field from data defined properties and update the corresponding button.
void setFormat(const QgsTextFormat &format)
Sets the current formatting settings.
QButtonGroup * mDirectSymbBtnGrp
Symbol direction button group.
void updateWidgetForFormat(const QgsTextFormat &format)
Updates the widget's state to reflect the settings in a QgsTextFormat.
QList< QgsSymbolLayerReference > mMaskedSymbolLayers
void widgetChanged()
Emitted when the text format defined by the widget changes.
void setPreviewBackground(const QColor &color)
Sets the background color for the text preview widget.
QButtonGroup * mQuadrantBtnGrp
Quadrant button group.
QgsWkbTypes::GeometryType labelGeometryType() const
Returns the geometry type which will be used by the labeling engine when registering labels for the l...
QgsWkbTypes::GeometryType mGeomType
Geometry type for layer, if known.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsSymbolWidgetContext mContext
Context in which widget is shown.
void updateLinePlacementOptions()
Updates line placement options to reflect current state of widget.
void populateDataDefinedButtons()
Sets up connections required for data defined buttons, or updates the existing definition of these bu...
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
void updatePreview()
Updates the text preview.
void auxiliaryFieldCreated()
Emitted when an auxiliary field is created in the widget.
virtual void setFormatFromStyle(const QString &name, QgsStyle::StyleEntity type, const QString &stylePath)
Sets the current text settings from a style entry.
QgsStringReplacementCollection mSubstitutions
Text substitution list.
@ Text
Default mode, show text formatting settings only.
@ Labeling
Show labeling settings in addition to text formatting settings.
virtual void saveFormat()
Saves the current text settings to a style entry.
QgsPropertyCollection mDataDefinedProperties
Data defined properties as defined in the widget.
QgsVectorLayer * mLayer
Associated vector layer.
Container for all settings relating to text rendering.
Definition: qgstextformat.h:41
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the text.
void setSize(double size)
Sets the size for rendered text.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the size.
void setCapitalization(Qgis::Capitalization capitalization)
Sets the text capitalization style.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the format's property collection, used for data defined overrides.
void setFont(const QFont &font)
Sets the font used for rendering text.
double lineHeight() const
Returns the line height for text.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
int stretchFactor() const
Returns the text's stretch factor.
void setOrientation(TextOrientation orientation)
Sets the orientation for the text.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the format's property collection, used for data defined overrides.
void setStretchFactor(int factor)
Sets the text's stretch factor.
void setShadow(const QgsTextShadowSettings &shadowSettings)
Sets the text's drop shadow settings.
void setMask(const QgsTextMaskSettings &maskSettings)
Sets the text's masking settings.
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 setPreviewBackgroundColor(const QColor &color)
Sets the background color that text will be rendered on for previews.
void setOpacity(double opacity)
Sets the text's opacity.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the text.
TextOrientation orientation() const
Returns the orientation of the text.
void setAllowHtmlFormatting(bool allow)
Sets whether text should be treated as a HTML document and HTML tags should be used for formatting th...
Qgis::Capitalization capitalization() const
Returns the text capitalization style.
QString resolvedFontFamily() const
Returns the family for the resolved font, ie if the specified font was not found on the system this w...
QgsTextMaskSettings & mask()
Returns a reference to the masking settings.
bool isValid() const
Returns true if the format is valid.
void setBuffer(const QgsTextBufferSettings &bufferSettings)
Sets the text's buffer settings.
QgsTextBackgroundSettings & background()
Returns a reference to the text background settings.
TextOrientation
Text orientation.
Definition: qgstextformat.h:46
@ HorizontalOrientation
Vertically oriented text.
Definition: qgstextformat.h:47
@ RotationBasedOrientation
Horizontally or vertically oriented text based on rotation (only available for map labeling)
Definition: qgstextformat.h:49
@ VerticalOrientation
Horizontally oriented text.
Definition: qgstextformat.h:48
bool allowHtmlFormatting() const
Returns true if text should be treated as a HTML document and HTML tags should be used for formatting...
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
double opacity() const
Returns the text's opacity.
QString namedStyle() const
Returns the named style for the font used for rendering text (e.g., "bold").
double size() const
Returns the size for rendered text.
QgsTextShadowSettings & shadow()
Returns a reference to the text drop shadow settings.
void setBackground(const QgsTextBackgroundSettings &backgroundSettings)
Sets the text's background settings.q.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the size.
void setNamedStyle(const QString &style)
Sets the named style for the font used for rendering text.
QColor color() const
Returns the color that text will be rendered in.
QFont font() const
Returns the font used for rendering text.
QColor previewBackgroundColor() const
Returns the background color for text previews.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
void setLineHeight(double height)
Sets the line height for text.
Container for settings relating to a selective masking around a text.
void setEnabled(bool)
Returns whether the mask is enabled.
void setMaskedSymbolLayers(const QList< QgsSymbolLayerReference > &maskedLayers)
Sets the symbol layers that will be masked by this buffer.
QList< QgsSymbolLayerReference > maskedSymbolLayers() const
Returns a list of references to symbol layers that are masked by this buffer.
void setSize(double size)
Sets the size of the buffer.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
double size() const
Returns the size of the buffer.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the buffer size.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the mask.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the buffer.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
double opacity() const
Returns the mask's opacity.
bool enabled() const
Returns whether the mask is enabled.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the mask.
Qt::PenJoinStyle joinStyle() const
Returns the buffer join style.
void setOpacity(double opacity)
Sets the mask's opacity.
Container for settings relating to a text shadow.
int offsetAngle() const
Returns the angle for offsetting the position of the shadow from the text.
void setBlurRadiusMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shadow blur radius.
bool enabled() const
Returns whether the shadow is enabled.
int scale() const
Returns the scaling used for the drop shadow (in percentage of original size).
void setShadowPlacement(QgsTextShadowSettings::ShadowPlacement placement)
Sets the placement for the drop shadow.
double opacity() const
Returns the shadow's opacity.
QgsMapUnitScale blurRadiusMapUnitScale() const
Returns the map unit scale object for the shadow blur radius.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the shadow offset distance.
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the drop shadow.
void setColor(const QColor &color)
Sets the color for the drop shadow.
QColor color() const
Returns the color of the drop shadow.
void setOffsetGlobal(bool global)
Sets whether the global shadow offset should be used.
ShadowPlacement
Placement positions for text shadow.
@ ShadowBuffer
Draw shadow under buffer.
@ ShadowShape
Draw shadow under background shape.
@ ShadowLowest
Draw shadow below all text components.
@ ShadowText
Draw shadow under text.
void setScale(int scale)
Sets the scaling used for the drop shadow (in percentage of original size).
void setBlurAlphaOnly(bool alphaOnly)
Sets whether only the alpha channel for the shadow should be blurred.
QgsTextShadowSettings::ShadowPlacement shadowPlacement() const
Returns the placement for the drop shadow.
double offsetDistance() const
Returns the distance for offsetting the position of the shadow from the text.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the drop shadow.
void setOffsetDistance(double distance)
Sets the distance for offsetting the position of the shadow from the text.
void setOpacity(double opacity)
Sets the shadow's opacity.
QgsMapUnitScale offsetMapUnitScale() const
Returns the map unit scale object for the shadow offset distance.
QgsUnitTypes::RenderUnit blurRadiusUnit() const
Returns the units used for the shadow's blur radius.
bool blurAlphaOnly() const
Returns whether only the alpha channel for the shadow will be blurred.
bool offsetGlobal() const
Returns true if the global shadow offset will be used.
void setOffsetAngle(int angle)
Sets the angle for offsetting the position of the shadow from the text.
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units used for the shadow's offset.
void setBlurRadiusUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shadow's blur radius.
double blurRadius() const
Returns the blur radius for the shadow.
void setBlurRadius(double blurRadius)
Sets the blur radius for the shadow.
void setOffsetUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shadow's offset.
void setEnabled(bool enabled)
Sets whether the text shadow will be drawn.
A widget displaying a combobox allowing the user to choose between various display units,...
QList< QgsUnitTypes::RenderUnit > RenderUnitList
List of render units.
Definition: qgsunittypes.h:240
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:176
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
Definition: qgsunittypes.h:172
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:173
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:171
@ RenderInches
Inches.
Definition: qgsunittypes.h:174
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:2186