QGIS API Documentation 4.3.0-Master (16eddb2670e)
Loading...
Searching...
No Matches
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 "qgsconfig.h"
17#include "qgstextformatwidget.h"
18
19#include "qgsauxiliarystorage.h"
22#include "qgsfillsymbol.h"
23#include "qgsfontutils.h"
24#include "qgsgeos.h"
25#include "qgsgui.h"
26#include "qgshelp.h"
27#include "qgsiconutils.h"
28#include "qgslogger.h"
29#include "qgsmapcanvas.h"
30#include "qgsmaplayer.h"
31#include "qgsmarkersymbol.h"
32#include "qgsmeshlayer.h"
34#include "qgspainteffect.h"
36#include "qgspallabeling.h"
37#include "qgspathresolver.h"
38#include "qgsproject.h"
41#include "qgssettings.h"
42#include "qgsstylesavedialog.h"
44#include "qgssvgcache.h"
47#include "qgssymbollayerutils.h"
49#include "qgsvectorlayer.h"
50
51#include <QButtonGroup>
52#include <QMessageBox>
53#include <QString>
54
55#include "moc_qgstextformatwidget.cpp"
56
57using namespace Qt::StringLiterals;
58
60 : QWidget( parent )
61 , mMapCanvas( mapCanvas )
62 , mLayer( layer )
63{
64 initWidget();
65 setWidgetMode( Text );
68}
69
70QgsTextFormatWidget::QgsTextFormatWidget( QgsMapCanvas *mapCanvas, QWidget *parent, Mode mode, QgsMapLayer *layer )
71 : QWidget( parent )
72 , mMapCanvas( mapCanvas )
73 , mLayer( layer )
74 , mWidgetMode( mode )
75{
76 initWidget();
77 if ( mode == Text )
79 setWidgetMode( mode );
80}
81
82void QgsTextFormatWidget::initWidget()
83{
84 setupUi( this );
85
86 mGeometryGeneratorGroupBox->setCollapsed( true );
87
88 mTextItem = new QListWidgetItem( tr( "Text" ), mLabelingOptionsListWidget );
89 mTextItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/labeltext.svg"_s ) );
90 mTextItem->setToolTip( tr( "Text style" ) );
91
92 mFormattingItem = new QListWidgetItem( tr( "Formatting" ), mLabelingOptionsListWidget );
93 mFormattingItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/labelformatting.svg"_s ) );
94 mFormattingItem->setToolTip( tr( "Formatting" ) );
95
96 mBufferItem = new QListWidgetItem( tr( "Buffer" ), mLabelingOptionsListWidget );
97 mBufferItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/labelbuffer.svg"_s ) );
98 mBufferItem->setToolTip( tr( "Buffer" ) );
99
100 mMaskItem = new QListWidgetItem( tr( "Mask" ), mLabelingOptionsListWidget );
101 mMaskItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/labelmask.svg"_s ) );
102 mMaskItem->setToolTip( tr( "Mask" ) );
103
104 mBackgroundItem = new QListWidgetItem( tr( "Background" ), mLabelingOptionsListWidget );
105 mBackgroundItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/labelbackground.svg"_s ) );
106 mBackgroundItem->setToolTip( tr( "Background" ) );
107
108 mShadowItem = new QListWidgetItem( tr( "Shadow" ), mLabelingOptionsListWidget );
109 mShadowItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/labelshadow.svg"_s ) );
110 mShadowItem->setToolTip( tr( "Shadow" ) );
111
112 mCalloutItem = new QListWidgetItem( tr( "Callouts" ), mLabelingOptionsListWidget );
113 mCalloutItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/labelcallout.svg"_s ) );
114 mCalloutItem->setToolTip( tr( "Callouts" ) );
115
116 mPlacementItem = new QListWidgetItem( tr( "Placement" ), mLabelingOptionsListWidget );
117 mPlacementItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/labelplacement.svg"_s ) );
118 mPlacementItem->setToolTip( tr( "Placement" ) );
119
120 mRenderingItem = new QListWidgetItem( tr( "Rendering" ), mLabelingOptionsListWidget );
121 mRenderingItem->setIcon( QgsApplication::getThemeIcon( u"propertyicons/render.svg"_s ) );
122 mRenderingItem->setToolTip( tr( "Rendering" ) );
123
124#if GEOS_VERSION_NUM < GEOS_COMPUTE_VERSION( 3, 10, 0 )
125 mDuplicatesStackedWidget->setCurrentWidget( mDuplicatesNotAvailableWidget );
126 mLabelSpacingStackedWidget->setCurrentWidget( mLabelSpacingNotAvailableWidget );
127#endif
128
129 mLabelingOptionsListWidget->addItem( mTextItem );
130 mLabelingOptionsListWidget->addItem( mFormattingItem );
131 mLabelingOptionsListWidget->addItem( mBufferItem );
132 mLabelingOptionsListWidget->addItem( mMaskItem );
133 mLabelingOptionsListWidget->addItem( mBackgroundItem );
134 mLabelingOptionsListWidget->addItem( mShadowItem );
135 mLabelingOptionsListWidget->addItem( mCalloutItem );
136 mLabelingOptionsListWidget->addItem( mPlacementItem );
137 mLabelingOptionsListWidget->addItem( mRenderingItem );
138
139 QObject::connect( mOptionsTab, &QTabWidget::currentChanged, this, [this]( int index ) {
140 if ( index == mOptionsTab->indexOf( textTab ) )
141 mLabelStackedWidget->setCurrentWidget( mLabelPage_Text );
142 else if ( index == mOptionsTab->indexOf( formattingTab ) )
143 mLabelStackedWidget->setCurrentWidget( mLabelPage_Formatting );
144 else if ( index == mOptionsTab->indexOf( maskTab ) )
145 mLabelStackedWidget->setCurrentWidget( mLabelPage_Mask );
146 else if ( index == mOptionsTab->indexOf( bufferTab ) )
147 mLabelStackedWidget->setCurrentWidget( mLabelPage_Buffer );
148 else if ( index == mOptionsTab->indexOf( backgroundTab ) )
149 mLabelStackedWidget->setCurrentWidget( mLabelPage_Background );
150 else if ( index == mOptionsTab->indexOf( shadowTab ) )
151 mLabelStackedWidget->setCurrentWidget( mLabelPage_Shadow );
152 else if ( index == mOptionsTab->indexOf( calloutsTab ) )
153 mLabelStackedWidget->setCurrentWidget( mLabelPage_Callouts );
154 else if ( index == mOptionsTab->indexOf( placementTab ) )
155 mLabelStackedWidget->setCurrentWidget( mLabelPage_Placement );
156 else if ( index == mOptionsTab->indexOf( renderingTab ) )
157 mLabelStackedWidget->setCurrentWidget( mLabelPage_Rendering );
158 } );
159
160 QObject::connect( mLabelingOptionsListWidget, &QListWidget::currentRowChanged, this, [this]( int ) {
161 QListWidgetItem *currentItem = mLabelingOptionsListWidget->currentItem();
162 if ( !currentItem )
163 return;
164 if ( currentItem == mTextItem )
165 mLabelStackedWidget->setCurrentWidget( mLabelPage_Text );
166 else if ( currentItem == mFormattingItem )
167 mLabelStackedWidget->setCurrentWidget( mLabelPage_Formatting );
168 else if ( currentItem == mMaskItem )
169 mLabelStackedWidget->setCurrentWidget( mLabelPage_Mask );
170 else if ( currentItem == mBufferItem )
171 mLabelStackedWidget->setCurrentWidget( mLabelPage_Buffer );
172 else if ( currentItem == mBackgroundItem )
173 mLabelStackedWidget->setCurrentWidget( mLabelPage_Background );
174 else if ( currentItem == mShadowItem )
175 mLabelStackedWidget->setCurrentWidget( mLabelPage_Shadow );
176 else if ( currentItem == mCalloutItem )
177 mLabelStackedWidget->setCurrentWidget( mLabelPage_Callouts );
178 else if ( currentItem == mPlacementItem )
179 mLabelStackedWidget->setCurrentWidget( mLabelPage_Placement );
180 else if ( currentItem == mRenderingItem )
181 mLabelStackedWidget->setCurrentWidget( mLabelPage_Rendering );
182 } );
183
184 QObject::connect( mLabelingOptionsListWidget, &QListWidget::currentRowChanged, mLabelStackedWidget, &QStackedWidget::setCurrentIndex );
185
186 connect( mShapeSVGPathLineEdit, &QLineEdit::textChanged, this, &QgsTextFormatWidget::mShapeSVGPathLineEdit_textChanged );
187 connect( mFontSizeSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontSizeSpinBox_valueChanged );
188 connect( mFontFamilyCmbBx, &QFontComboBox::currentFontChanged, this, &QgsTextFormatWidget::mFontFamilyCmbBx_currentFontChanged );
189 connect( mFontStyleComboBox, &QComboBox::currentTextChanged, this, &QgsTextFormatWidget::mFontStyleComboBox_currentIndexChanged );
190 connect( mFontUnderlineBtn, &QToolButton::toggled, this, &QgsTextFormatWidget::mFontUnderlineBtn_toggled );
191 connect( mFontStrikethroughBtn, &QToolButton::toggled, this, &QgsTextFormatWidget::mFontStrikethroughBtn_toggled );
192 connect( mFontWordSpacingSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontWordSpacingSpinBox_valueChanged );
193 connect( mFontLetterSpacingSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontLetterSpacingSpinBox_valueChanged );
194 connect( mFontSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsTextFormatWidget::mFontSizeUnitWidget_changed );
195 connect( mFontMinPixelSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontMinPixelSpinBox_valueChanged );
196 connect( mFontMaxPixelSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsTextFormatWidget::mFontMaxPixelSpinBox_valueChanged );
197 connect( mBufferUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsTextFormatWidget::mBufferUnitWidget_changed );
198 connect( mMaskBufferUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsTextFormatWidget::mMaskBufferUnitWidget_changed );
199 connect( mCoordXDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::mCoordXDDBtn_changed );
200 connect( mCoordXDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::mCoordXDDBtn_activated );
201 connect( mCoordYDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::mCoordYDDBtn_changed );
202 connect( mCoordYDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::mCoordYDDBtn_activated );
203 connect( mCoordPointDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::mCoordPointDDBtn_changed );
204 connect( mCoordPointDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::mCoordPointDDBtn_activated );
205 connect( mShapeTypeCmbBx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::mShapeTypeCmbBx_currentIndexChanged );
206 connect( mShapeRotationCmbBx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::mShapeRotationCmbBx_currentIndexChanged );
207 connect( mShapeSVGParamsBtn, &QPushButton::clicked, this, &QgsTextFormatWidget::mShapeSVGParamsBtn_clicked );
208 connect( mShapeSVGSelectorBtn, &QPushButton::clicked, this, &QgsTextFormatWidget::mShapeSVGSelectorBtn_clicked );
209 connect( mPreviewTextEdit, &QLineEdit::textChanged, this, &QgsTextFormatWidget::mPreviewTextEdit_textChanged );
210 connect( mPreviewTextBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mPreviewTextBtn_clicked );
211 connect( mPreviewBackgroundBtn, &QgsColorButton::colorChanged, this, &QgsTextFormatWidget::mPreviewBackgroundBtn_colorChanged );
212 connect( mDirectSymbLeftToolBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mDirectSymbLeftToolBtn_clicked );
213 connect( mDirectSymbRightToolBtn, &QToolButton::clicked, this, &QgsTextFormatWidget::mDirectSymbRightToolBtn_clicked );
214 connect( chkLineOrientationDependent, &QCheckBox::toggled, this, &QgsTextFormatWidget::chkLineOrientationDependent_toggled );
215 connect( mToolButtonConfigureSubstitutes, &QToolButton::clicked, this, &QgsTextFormatWidget::mToolButtonConfigureSubstitutes_clicked );
216 connect( mKerningCheckBox, &QCheckBox::toggled, this, &QgsTextFormatWidget::kerningToggled );
217 connect( mComboOverlapHandling, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::overlapModeChanged );
218 connect( mTabStopsButton, &QToolButton::clicked, this, &QgsTextFormatWidget::configureTabStops );
219
220 const int iconSize = QgsGuiUtils::scaleIconSize( 20 );
221 mOptionsTab->setIconSize( QSize( iconSize, iconSize ) );
222 mLabelingOptionsListWidget->setIconSize( QSize( iconSize, iconSize ) );
223 const int iconSize32 = QgsGuiUtils::scaleIconSize( 32 );
224 const int iconSize24 = QgsGuiUtils::scaleIconSize( 24 );
225 const int iconSize18 = QgsGuiUtils::scaleIconSize( 18 );
226 const int iconSize16 = QgsGuiUtils::scaleIconSize( 16 );
227
228 mPreviewTextBtn->setIconSize( QSize( iconSize16, iconSize16 ) );
229 mPointOffsetAboveLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
230 mPointOffsetAbove->setIconSize( QSize( iconSize32, iconSize18 ) );
231 mPointOffsetAboveRight->setIconSize( QSize( iconSize32, iconSize18 ) );
232 mPointOffsetLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
233 mPointOffsetOver->setIconSize( QSize( iconSize32, iconSize18 ) );
234 mPointOffsetRight->setIconSize( QSize( iconSize32, iconSize18 ) );
235 mPointOffsetBelowLeft->setIconSize( QSize( iconSize32, iconSize18 ) );
236 mPointOffsetBelow->setIconSize( QSize( iconSize32, iconSize18 ) );
237 mPointOffsetBelowRight->setIconSize( QSize( iconSize32, iconSize18 ) );
238 mLabelMinScale->setPixmap( QgsApplication::getThemeIcon( u"/mActionZoomOut.svg"_s ).pixmap( QSize( iconSize24, iconSize24 ) ) );
239 mLabelMaxScale->setPixmap( QgsApplication::getThemeIcon( u"/mActionZoomIn.svg"_s ).pixmap( QSize( iconSize24, iconSize24 ) ) );
240
241 const int buttonSize = QgsGuiUtils::scaleIconSize( 24 );
242 mFontUnderlineBtn->setMinimumSize( buttonSize, buttonSize );
243 mFontUnderlineBtn->setMaximumSize( buttonSize, buttonSize );
244 mFontStrikethroughBtn->setMinimumSize( buttonSize, buttonSize );
245 mFontStrikethroughBtn->setMaximumSize( buttonSize, buttonSize );
246 mFontBoldBtn->setMinimumSize( buttonSize, buttonSize );
247 mFontBoldBtn->setMaximumSize( buttonSize, buttonSize );
248 mFontItalicBtn->setMinimumSize( buttonSize, buttonSize );
249 mFontItalicBtn->setMaximumSize( buttonSize, buttonSize );
250
251 mPreviewScaleComboBox->setMapCanvas( mMapCanvas );
252 mPreviewScaleComboBox->setShowCurrentScaleButton( true );
253 connect( mPreviewScaleComboBox, &QgsScaleWidget::scaleChanged, this, &QgsTextFormatWidget::previewScaleChanged );
254
255 const auto unitWidgets = findChildren<QgsUnitSelectionWidget *>();
256 for ( QgsUnitSelectionWidget *unitWidget : unitWidgets )
257 {
258 unitWidget->setMapCanvas( mMapCanvas );
259 }
260 mFontSizeUnitWidget->setUnits(
262 );
263 mBufferUnitWidget->setUnits(
272 );
273 mMaskBufferUnitWidget->setUnits(
282 );
283 mShapeSizeUnitWidget->setUnits(
285 );
286 mShapeOffsetUnitWidget->setUnits(
288 );
289 mShapeRadiusUnitWidget->setUnits(
298 );
299 mShapeStrokeWidthUnitWidget->setUnits(
301 );
302 mShadowOffsetUnitWidget->setUnits(
311 );
312 mShadowRadiusUnitWidget->setUnits(
321 );
322 mPointOffsetUnitWidget->setUnits(
324 );
325 mLineDistanceUnitWidget->setUnits(
327 );
328 mMaximumDistanceUnitWidget->setUnits(
330 );
331 mRepeatDistanceUnitWidget->setUnits(
333 );
334 mOverrunDistanceUnitWidget->setUnits(
336 );
337 mLabelMarginUnitWidget->setUnits(
339 );
340 mLineHeightUnitWidget->setUnits(
342 );
343 mTabDistanceUnitWidget->setUnits(
345 );
346 mFontLineHeightSpinBox->setClearValue( 100.0 );
347 mShapeRotationDblSpnBx->setClearValue( 0.0 );
348 mShapeOffsetXSpnBx->setClearValue( 0.0 );
349 mShapeOffsetYSpnBx->setClearValue( 0.0 );
350 mPointOffsetXSpinBox->setClearValue( 0.0 );
351 mPointOffsetYSpinBox->setClearValue( 0.0 );
352 mPointAngleSpinBox->setClearValue( 0.0 );
353 mFontLetterSpacingSpinBox->setClearValue( 0.0 );
354 mFontWordSpacingSpinBox->setClearValue( 0.0 );
355 mZIndexSpinBox->setClearValue( 0.0 );
356 mLineDistanceSpnBx->setClearValue( 0.0 );
357 mMaximumDistanceSpnBx->setMinimum( 0 );
358 mMaximumDistanceSpnBx->setClearValue( 0.0, tr( "Not set" ) );
359 mSpinStretch->setClearValue( 100 );
360 mTabStopDistanceSpin->setMinimum( 0 );
361
362 connect( mLineHeightUnitWidget, &QgsUnitSelectionWidget::changed, this, [this] {
363 if ( mLineHeightUnitWidget->unit() == Qgis::RenderUnit::Percentage )
364 mFontLineHeightSpinBox->setClearValue( 100.0 );
365 else
366 mFontLineHeightSpinBox->setClearValue( 10.0 );
367 } );
368
369 mOffsetTypeComboBox->addItem( tr( "From Point" ), static_cast<int>( Qgis::LabelOffsetType::FromPoint ) );
370 mOffsetTypeComboBox->addItem( tr( "From Symbol Bounds" ), static_cast<int>( Qgis::LabelOffsetType::FromSymbolBounds ) );
371
372 mShapeTypeCmbBx->addItem( tr( "Rectangle" ), QgsTextBackgroundSettings::ShapeRectangle );
373 mShapeTypeCmbBx->addItem( tr( "Square" ), QgsTextBackgroundSettings::ShapeSquare );
374 mShapeTypeCmbBx->addItem( tr( "Ellipse" ), QgsTextBackgroundSettings::ShapeEllipse );
375 mShapeTypeCmbBx->addItem( tr( "Circle" ), QgsTextBackgroundSettings::ShapeCircle );
376 mShapeTypeCmbBx->addItem( tr( "SVG" ), QgsTextBackgroundSettings::ShapeSVG );
377 mShapeTypeCmbBx->addItem( tr( "Marker Symbol" ), QgsTextBackgroundSettings::ShapeMarkerSymbol );
378
379 mComboOverlapHandling->addItem( tr( "Never Overlap" ), static_cast<int>( Qgis::LabelOverlapHandling::PreventOverlap ) );
380 mComboOverlapHandling->addItem( tr( "Allow Overlaps if Required" ), static_cast<int>( Qgis::LabelOverlapHandling::AllowOverlapIfRequired ) );
381 mComboOverlapHandling->addItem( tr( "Allow Overlaps without Penalty" ), static_cast<int>( Qgis::LabelOverlapHandling::AllowOverlapAtNoCost ) );
382
383 mPrioritizationComboBox->addItem( tr( "Prefer Closer Labels" ), QVariant::fromValue( Qgis::LabelPrioritization::PreferCloser ) );
384 mPrioritizationComboBox->addItem( tr( "Prefer Position Ordering" ), QVariant::fromValue( Qgis::LabelPrioritization::PreferPositionOrdering ) );
385
386 mComboCurvedLabelMode->addItem( tr( "Default" ), QVariant::fromValue( Qgis::CurvedLabelMode::Default ) );
387 mComboCurvedLabelMode->addItem( tr( "Stretch Word Spacing" ), QVariant::fromValue( Qgis::CurvedLabelMode::StretchWordSpacingToFitLine ) );
388 mComboCurvedLabelMode->addItem( tr( "Stretch Character Spacing" ), QVariant::fromValue( Qgis::CurvedLabelMode::StretchCharacterSpacingToFitLine ) );
389 mComboCurvedLabelMode->addItem( tr( "Characters at Vertices" ), QVariant::fromValue( Qgis::CurvedLabelMode::PlaceCharactersAtVertices ) );
390 connect( mComboCurvedLabelMode, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::updateCurvedLabelDescription );
391 QFont font = mCurvedModeDescriptionLabel->font();
392 font.setItalic( true );
393 mCurvedModeDescriptionLabel->setFont( font );
394 updateCurvedLabelDescription();
395
396 mComboMultipartBehavior->addItem( tr( "Label Largest Part Only" ), QVariant::fromValue( Qgis::MultiPartLabelingBehavior::LabelLargestPartOnly ) );
397 mComboMultipartBehavior->addItem( tr( "Label Every Part with Entire Label" ), QVariant::fromValue( Qgis::MultiPartLabelingBehavior::LabelEveryPartWithEntireLabel ) );
398 mComboMultipartBehavior->addItem( tr( "Split Label Text Lines over Parts" ), QVariant::fromValue( Qgis::MultiPartLabelingBehavior::SplitLabelTextLinesOverParts ) );
399
400 updateAvailableShadowPositions();
401
402 mBackgroundMarkerSymbolButton->setSymbolType( Qgis::SymbolType::Marker );
403 mBackgroundMarkerSymbolButton->setDialogTitle( tr( "Background Symbol" ) );
404 mBackgroundMarkerSymbolButton->registerExpressionContextGenerator( this );
405 mBackgroundMarkerSymbolButton->setMapCanvas( mMapCanvas );
406 mBackgroundFillSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
407 mBackgroundFillSymbolButton->setDialogTitle( tr( "Background Symbol" ) );
408 mBackgroundFillSymbolButton->registerExpressionContextGenerator( this );
409 mBackgroundFillSymbolButton->setMapCanvas( mMapCanvas );
410
411 mCharDlg = new QgsCharacterSelectorDialog( this );
412
413 mRefFont = lblFontPreview->font();
414
415 // internal connections
416 connect( mShadowOffsetAngleDial, &QAbstractSlider::valueChanged, mShadowOffsetAngleSpnBx, &QSpinBox::setValue );
417 connect( mShadowOffsetAngleSpnBx, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), mShadowOffsetAngleDial, &QAbstractSlider::setValue );
418 connect( mLimitLabelChkBox, &QAbstractButton::toggled, mLimitLabelSpinBox, &QWidget::setEnabled );
419 connect( mCheckBoxSubstituteText, &QAbstractButton::toggled, mToolButtonConfigureSubstitutes, &QWidget::setEnabled );
420
421 //connections to prevent users removing all line placement positions
422 connect( chkLineAbove, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
423 connect( chkLineBelow, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
424 connect( chkLineOn, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updateLinePlacementOptions );
425
426 mTextOrientationComboBox->addItem( tr( "Horizontal" ), static_cast<int>( Qgis::TextOrientation::Horizontal ) );
427 mTextOrientationComboBox->addItem( tr( "Vertical" ), static_cast<int>( Qgis::TextOrientation::Vertical ) );
428
429 populateFontCapitalsComboBox();
430
431 // color buttons
432 mPreviewBackgroundBtn->setColorDialogTitle( tr( "Select Fill Color" ) );
433 mPreviewBackgroundBtn->setContext( u"labeling"_s );
434 mPreviewBackgroundBtn->setColor( QColor( 255, 255, 255 ) );
435 btnTextColor->setColorDialogTitle( tr( "Select Text Color" ) );
436 btnTextColor->setContext( u"labeling"_s );
437 btnTextColor->setDefaultColor( Qt::black );
438 btnBufferColor->setColorDialogTitle( tr( "Select Buffer Color" ) );
439 btnBufferColor->setContext( u"labeling"_s );
440 btnBufferColor->setDefaultColor( Qt::white );
441 mShapeStrokeColorBtn->setColorDialogTitle( tr( "Select Stroke Color" ) );
442 mShapeStrokeColorBtn->setContext( u"labeling"_s );
443 mShapeFillColorBtn->setColorDialogTitle( tr( "Select Fill Color" ) );
444 mShapeFillColorBtn->setContext( u"labeling"_s );
445 mShadowColorBtn->setColorDialogTitle( tr( "Select Shadow Color" ) );
446 mShadowColorBtn->setContext( u"labeling"_s );
447 mShadowColorBtn->setDefaultColor( Qt::black );
448
449 mFontColorDDBtn->registerLinkedWidget( btnTextColor );
450 mBufferColorDDBtn->registerLinkedWidget( btnBufferColor );
451 mShapeStrokeColorDDBtn->registerLinkedWidget( mShapeStrokeColorBtn );
452 mShapeFillColorDDBtn->registerLinkedWidget( mShapeFillColorBtn );
453 mShadowColorDDBtn->registerLinkedWidget( mShadowColorBtn );
454
455 // set up quadrant offset button group
456 mQuadrantBtnGrp = new QButtonGroup( this );
457 mQuadrantBtnGrp->addButton( mPointOffsetAboveLeft, static_cast<int>( Qgis::LabelQuadrantPosition::AboveLeft ) );
458 mQuadrantBtnGrp->addButton( mPointOffsetAbove, static_cast<int>( Qgis::LabelQuadrantPosition::Above ) );
459 mQuadrantBtnGrp->addButton( mPointOffsetAboveRight, static_cast<int>( Qgis::LabelQuadrantPosition::AboveRight ) );
460 mQuadrantBtnGrp->addButton( mPointOffsetLeft, static_cast<int>( Qgis::LabelQuadrantPosition::Left ) );
461 mQuadrantBtnGrp->addButton( mPointOffsetOver, static_cast<int>( Qgis::LabelQuadrantPosition::Over ) );
462 mQuadrantBtnGrp->addButton( mPointOffsetRight, static_cast<int>( Qgis::LabelQuadrantPosition::Right ) );
463 mQuadrantBtnGrp->addButton( mPointOffsetBelowLeft, static_cast<int>( Qgis::LabelQuadrantPosition::BelowLeft ) );
464 mQuadrantBtnGrp->addButton( mPointOffsetBelow, static_cast<int>( Qgis::LabelQuadrantPosition::Below ) );
465 mQuadrantBtnGrp->addButton( mPointOffsetBelowRight, static_cast<int>( Qgis::LabelQuadrantPosition::BelowRight ) );
466 mQuadrantBtnGrp->setExclusive( true );
467
468 // setup direction symbol(s) button group
469 mDirectSymbBtnGrp = new QButtonGroup( this );
470 mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnLR, static_cast<int>( QgsLabelLineSettings::DirectionSymbolPlacement::SymbolLeftRight ) );
471 mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnAbove, static_cast<int>( QgsLabelLineSettings::DirectionSymbolPlacement::SymbolAbove ) );
472 mDirectSymbBtnGrp->addButton( mDirectSymbRadioBtnBelow, static_cast<int>( QgsLabelLineSettings::DirectionSymbolPlacement::SymbolBelow ) );
473 mDirectSymbBtnGrp->setExclusive( true );
474
475 // upside-down labels button group
476 mUpsidedownBtnGrp = new QButtonGroup( this );
477 mUpsidedownBtnGrp->addButton( mUpsidedownRadioOff, static_cast<int>( Qgis::UpsideDownLabelHandling::FlipUpsideDownLabels ) );
478 mUpsidedownBtnGrp->addButton( mUpsidedownRadioDefined, static_cast<int>( Qgis::UpsideDownLabelHandling::AllowUpsideDownWhenRotationIsDefined ) );
479 mUpsidedownBtnGrp->addButton( mUpsidedownRadioAll, static_cast<int>( Qgis::UpsideDownLabelHandling::AlwaysAllowUpsideDown ) );
480 mUpsidedownBtnGrp->setExclusive( true );
481
482 //mShapeCollisionsChkBx->setVisible( false ); // until implemented
483
484 // post updatePlacementWidgets() connections
485 connect( chkLineAbove, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updatePlacementWidgets );
486 connect( chkLineBelow, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updatePlacementWidgets );
487 connect( mCheckAllowLabelsOutsidePolygons, &QAbstractButton::toggled, this, &QgsTextFormatWidget::updatePlacementWidgets );
488 connect( mAllowOutsidePolygonsDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::updatePlacementWidgets );
489
490 connect( mPlacementModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::updatePlacementWidgets );
491
492 // Global settings group for groupboxes' saved/restored collapsed state
493 // maintains state across different dialogs
494 const auto groupBoxes = findChildren<QgsCollapsibleGroupBox *>();
495 for ( QgsCollapsibleGroupBox *grpbox : groupBoxes )
496 {
497 grpbox->setSettingGroup( u"mAdvLabelingDlg"_s );
498 }
499
500 connect( groupBox_mPreview, &QgsCollapsibleGroupBoxBasic::collapsedStateChanged, this, &QgsTextFormatWidget::collapseSample );
501
502 // get rid of annoying outer focus rect on Mac
503 mLabelingOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect, false );
504
505 const QgsSettings settings;
506
507 // reset horiz stretch of left side of options splitter (set to 1 for previewing in Qt Designer)
508 QSizePolicy policy( mLabelingOptionsListFrame->sizePolicy() );
509 policy.setHorizontalStretch( 0 );
510 mLabelingOptionsListFrame->setSizePolicy( policy );
511 if ( !settings.contains( u"/Windows/Labeling/OptionsSplitState"_s ) )
512 {
513 // set left list widget width on initial showing
514 QList<int> splitsizes;
515 splitsizes << 115;
516 mLabelingOptionsSplitter->setSizes( splitsizes );
517 }
518
519 // set up reverse connection from stack to list
520 connect( mLabelStackedWidget, &QStackedWidget::currentChanged, this, &QgsTextFormatWidget::optionsStackedWidget_CurrentChanged );
521
522 // restore dialog, splitters and current tab
523 mFontPreviewSplitter->restoreState( settings.value( u"Windows/Labeling/FontPreviewSplitState"_s ).toByteArray() );
524 mLabelingOptionsSplitter->restoreState( settings.value( u"Windows/Labeling/OptionsSplitState"_s ).toByteArray() );
525
526 mLabelingOptionsListWidget->setCurrentRow( settings.value( u"Windows/Labeling/Tab"_s, 0 ).toInt() );
527
528 mBufferEffect = QgsPaintEffectRegistry::defaultStack();
529 connect( mBufferEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
530 mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );
531
534 mMaskEffectWidget->setPaintEffect( mMaskEffect.get() );
535
536 mBackgroundEffect = QgsPaintEffectRegistry::defaultStack();
537 connect( mBackgroundEffectWidget, &QgsEffectStackCompactWidget::changed, this, &QgsTextFormatWidget::updatePreview );
538 mBackgroundEffectWidget->setPaintEffect( mBackgroundEffect.get() );
539
540 overlapModeChanged();
541
542 setDockMode( false );
543
544 QList<QWidget *> widgets;
545 widgets
546 << btnBufferColor
547 << btnTextColor
548 << mComboMultipartBehavior
549 << chkLineAbove
550 << chkLineBelow
551 << chkLineOn
552 << chkLineOrientationDependent
553 << chkMergeLines
554 << chkPreserveRotation
555 << comboBlendMode
556 << comboBufferBlendMode
557 << mBufferDrawChkBx
558 << mBufferJoinStyleComboBox
559 << mBufferTranspFillChbx
560 << mBufferOpacityWidget
561 << mCentroidInsideCheckBox
562 << mChkNoObstacle
563 << mCoordRotationUnitComboBox
564 << mDirectSymbChkBx
565 << mDirectSymbLeftLineEdit
566 << mDirectSymbRevChkBx
567 << mDirectSymbRightLineEdit
568 << mFitInsidePolygonCheckBox
569 << mFontCapitalsComboBox
570 << mFontLetterSpacingSpinBox
571 << mFontLimitPixelChkBox
572 << mFontLineHeightSpinBox
573 << mLineHeightUnitWidget
574 << mFontMaxPixelSpinBox
575 << mFontMinPixelSpinBox
576 << mFontMultiLineAlignComboBox
577 << mFontSizeSpinBox
578 << mFontStyleComboBox
579 << mTextOrientationComboBox
580 << mTextOpacityWidget
581 << mSpinStretch
582 << mFontWordSpacingSpinBox
583 << mFormatNumChkBx
584 << mFormatNumDecimalsSpnBx
585 << mFormatNumPlusSignChkBx
586 << mLimitLabelChkBox
587 << mLimitLabelSpinBox
588 << mLineDistanceSpnBx
589 << mLineDistanceUnitWidget
590 << mMaximumDistanceSpnBx
591 << mMaximumDistanceUnitWidget
592 << mMaxCharAngleInDSpinBox
593 << mMaxCharAngleOutDSpinBox
594 << mMinSizeSpinBox
595 << mOffsetTypeComboBox
596 << mCheckAllowDegradedPlacement
597 << mComboOverlapHandling
598 << mPointAngleSpinBox
599 << mPointOffsetUnitWidget
600 << mPointOffsetXSpinBox
601 << mPointOffsetYSpinBox
602 << mPreviewBackgroundBtn
603 << mPreviewTextEdit
604 << mPrioritySlider
605 << mRepeatDistanceSpinBox
606 << mRepeatDistanceUnitWidget
607 << mOverrunDistanceSpinBox
608 << mOverrunDistanceUnitWidget
609 << mLabelMarginSpinBox
610 << mLabelMarginUnitWidget
611 << mScaleBasedVisibilityChkBx
612 << mMaxScaleWidget
613 << mMinScaleWidget
614 << mShadowBlendCmbBx
615 << mShadowColorBtn
616 << mShadowDrawChkBx
617 << mShadowOffsetAngleSpnBx
618 << mShadowOffsetGlobalChkBx
619 << mShadowOffsetSpnBx
620 << mShadowOffsetUnitWidget
621 << mShadowRadiusAlphaChkBx
622 << mShadowRadiusDblSpnBx
623 << mShadowRadiusUnitWidget
624 << mShadowScaleSpnBx
625 << mShadowOpacityWidget
626 << mShadowUnderCmbBx
627 << mShapeBlendCmbBx
628 << mShapeStrokeColorBtn
629 << mShapeStrokeWidthSpnBx
630 << mShapeStrokeWidthUnitWidget
631 << mShapeDrawChkBx
632 << mShapeFillColorBtn
633 << mShapeOffsetXSpnBx
634 << mShapeOffsetYSpnBx
635 << mShapeOffsetUnitWidget
636 << mShapeRadiusXDbSpnBx
637 << mShapeRadiusYDbSpnBx
638 << mShapeRotationCmbBx
639 << mShapeRotationDblSpnBx
640 << mShapeRadiusUnitWidget
641 << mShapeSVGPathLineEdit
642 << mShapeSizeCmbBx
643 << mShapeSizeUnitWidget
644 << mShapeSizeXSpnBx
645 << mShapeSizeYSpnBx
646 << mBackgroundOpacityWidget
647 << mShapeTypeCmbBx
648 << mZIndexSpinBox
649 << spinBufferSize
650 << wrapCharacterEdit
651 << mAutoWrapLengthSpinBox
652 << mAutoWrapTypeComboBox
653 << mCentroidRadioVisible
654 << mCentroidRadioWhole
655 << mDirectSymbRadioBtnAbove
656 << mDirectSymbRadioBtnBelow
657 << mDirectSymbRadioBtnLR
658 << mUpsidedownRadioAll
659 << mUpsidedownRadioDefined
660 << mUpsidedownRadioOff
661 << mPlacementModeComboBox
662 << mFieldExpressionWidget
663 << mCheckBoxSubstituteText
664 << mGeometryGeneratorGroupBox
665 << mGeometryGenerator
666 << mGeometryGeneratorType
667 << mBackgroundMarkerSymbolButton
668 << mBackgroundFillSymbolButton
669 << mCalloutsDrawCheckBox
670 << mCalloutStyleComboBox
671 << mKerningCheckBox
672 << mEnableMaskChkBx
673 << mMaskJoinStyleComboBox
674 << mMaskBufferSizeSpinBox
675 << mMaskOpacityWidget
676 << mCheckAllowLabelsOutsidePolygons
677 << mHtmlFormattingCheckBox
678 << mPrioritizationComboBox
679 << mComboCurvedLabelMode
680 << mTabDistanceUnitWidget
681 << mTabStopDistanceSpin
682 << mChkNoDuplicates
683 << mCheckWhitespaceIsNotACollision;
684
685 connectValueChanged( widgets );
686
687 connect( mQuadrantBtnGrp, qOverload<QAbstractButton *>( &QButtonGroup::buttonClicked ), this, &QgsTextFormatWidget::updatePreview );
688
689 connect( mBufferDrawDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::updateBufferFrameStatus );
690 connect( mBufferDrawChkBx, &QCheckBox::stateChanged, this, [this]( int ) { updateBufferFrameStatus(); } );
691 connect( mShapeDrawDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::updateShapeFrameStatus );
692 connect( mShapeDrawChkBx, &QCheckBox::stateChanged, this, [this]( int ) { updateShapeFrameStatus(); } );
693 connect( mShadowDrawDDBtn, &QgsPropertyOverrideButton::activated, this, &QgsTextFormatWidget::updateShadowFrameStatus );
694 connect( mShadowDrawChkBx, &QCheckBox::stateChanged, this, [this]( int ) { updateShadowFrameStatus(); } );
695 connect( mCalloutDrawDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::updateCalloutFrameStatus );
696 connect( mCalloutsDrawCheckBox, &QCheckBox::stateChanged, this, [this]( int ) { updateCalloutFrameStatus(); } );
697
698 mGeometryGeneratorType->addItem( QgsIconUtils::iconForWkbType( Qgis::WkbType::Polygon ), tr( "Polygon / MultiPolygon" ), static_cast<int>( Qgis::GeometryType::Polygon ) );
699 mGeometryGeneratorType->addItem( QgsIconUtils::iconForWkbType( Qgis::WkbType::LineString ), tr( "LineString / MultiLineString" ), static_cast<int>( Qgis::GeometryType::Line ) );
700 mGeometryGeneratorType->addItem( QgsIconUtils::iconForWkbType( Qgis::WkbType::Point ), tr( "Point / MultiPoint" ), static_cast<int>( Qgis::GeometryType::Point ) );
701
702 // set correct initial tab to match displayed setting page
703 whileBlocking( mOptionsTab )->setCurrentIndex( mLabelStackedWidget->currentIndex() );
704 mOptionsTab->tabBar()->setUsesScrollButtons( true );
705
706
707 if ( mMapCanvas )
708 {
709 lblFontPreview->setMapUnits( mMapCanvas->mapSettings().mapUnits() );
710 mPreviewScaleComboBox->setScale( mMapCanvas->mapSettings().scale() );
711 }
712
713 mTextFormatsListWidget->setStyle( QgsStyle::defaultStyle() );
714 mTextFormatsListWidget->setEntityType( QgsStyle::TextFormatEntity );
716 connect( mTextFormatsListWidget, &QgsStyleItemsListWidget::saveEntity, this, &QgsTextFormatWidget::saveFormat );
717}
718
719void QgsTextFormatWidget::setWidgetMode( QgsTextFormatWidget::Mode mode )
720{
721 mWidgetMode = mode;
722 switch ( mode )
723 {
724 case Labeling:
726 mTextFormatsListWidget->setEntityTypes( QList<QgsStyle::StyleEntity>() << QgsStyle::TextFormatEntity << QgsStyle::LabelSettingsEntity );
727 mTextOrientationComboBox->addItem( tr( "Rotation-based" ), static_cast<int>( Qgis::TextOrientation::RotationBased ) );
728 break;
729
730 case Text:
731 {
732 const int prevIndex = mOptionsTab->currentIndex();
734 delete mRenderingItem;
735 mRenderingItem = nullptr;
736 delete mPlacementItem;
737 mPlacementItem = nullptr;
738 delete mCalloutItem;
739 mCalloutItem = nullptr;
740 delete mMaskItem;
741 mMaskItem = nullptr;
742 mOptionsTab->removeTab( mOptionsTab->indexOf( renderingTab ) );
743 mOptionsTab->removeTab( mOptionsTab->indexOf( placementTab ) );
744 mOptionsTab->removeTab( mOptionsTab->indexOf( calloutsTab ) );
745 mOptionsTab->removeTab( mOptionsTab->indexOf( maskTab ) );
746 mLabelStackedWidget->removeWidget( mLabelPage_Rendering );
747 mLabelStackedWidget->removeWidget( mLabelPage_Callouts );
748 mLabelStackedWidget->removeWidget( mLabelPage_Mask );
749 mLabelStackedWidget->removeWidget( mLabelPage_Placement );
750 switch ( prevIndex )
751 {
752 case 0:
753 case 1:
754 case 2:
755 break;
756
757 case 4: // background - account for removed mask tab
758 case 5: // shadow
759 mLabelStackedWidget->setCurrentIndex( prevIndex - 1 );
760 mOptionsTab->setCurrentIndex( prevIndex - 1 );
761 break;
762
763 case 3: // mask
764 case 6: // callouts
765 case 7: // placement
766 case 8: // rendering
767 mLabelStackedWidget->setCurrentIndex( 0 );
768 mOptionsTab->setCurrentIndex( 0 );
769 break;
770 }
771
772 mStackedWidgetLabelWith->hide();
773 mDirectSymbolsFrame->hide();
774 mFormatNumFrame->hide();
775 mFormatNumChkBx->hide();
776 mFormatNumDDBtn->hide();
777 mCheckBoxSubstituteText->hide();
778 mToolButtonConfigureSubstitutes->hide();
779 mLabelWrapOnCharacter->hide();
780 wrapCharacterEdit->hide();
781 mWrapCharDDBtn->hide();
782 mLabelWrapLinesTo->hide();
783 mAutoWrapLengthSpinBox->hide();
784 mAutoWrapLengthDDBtn->hide();
785 mAutoWrapTypeComboBox->hide();
786 mFontMultiLineLabel->hide();
787 mFontMultiLineAlignComboBox->hide();
788 mFontMultiLineAlignDDBtn->hide();
789
790 mTextOrientationComboBox->removeItem( mTextOrientationComboBox->findData( static_cast<int>( Qgis::TextOrientation::RotationBased ) ) );
791 break;
792 }
793 }
794}
795
797{
798 const QList<QgsPropertyOverrideButton *> buttons = findChildren<QgsPropertyOverrideButton *>();
799 for ( QgsPropertyOverrideButton *button : buttons )
800 {
801 button->setVisible( visible );
802 }
803}
804
806{
807 mOptionsTab->setVisible( enabled );
808 if ( int tabIndex = mOptionsTab->indexOf( textTab ); tabIndex >= 0 )
809 mOptionsTab->setTabToolTip( tabIndex, tr( "Text" ) );
810 if ( int tabIndex = mOptionsTab->indexOf( formattingTab ); tabIndex >= 0 )
811 mOptionsTab->setTabToolTip( tabIndex, tr( "Formatting" ) );
812 if ( int tabIndex = mOptionsTab->indexOf( bufferTab ); tabIndex >= 0 )
813 mOptionsTab->setTabToolTip( tabIndex, tr( "Buffer" ) );
814 if ( int tabIndex = mOptionsTab->indexOf( maskTab ); tabIndex >= 0 )
815 mOptionsTab->setTabToolTip( tabIndex, tr( "Mask" ) );
816 if ( int tabIndex = mOptionsTab->indexOf( backgroundTab ); tabIndex >= 0 )
817 mOptionsTab->setTabToolTip( tabIndex, tr( "Background" ) );
818 if ( int tabIndex = mOptionsTab->indexOf( shadowTab ); tabIndex >= 0 )
819 mOptionsTab->setTabToolTip( tabIndex, tr( "Shadow" ) );
820 if ( int tabIndex = mOptionsTab->indexOf( calloutsTab ); tabIndex >= 0 )
821 mOptionsTab->setTabToolTip( tabIndex, tr( "Callouts" ) );
822 if ( int tabIndex = mOptionsTab->indexOf( placementTab ); tabIndex >= 0 )
823 mOptionsTab->setTabToolTip( tabIndex, tr( "Placement" ) );
824 if ( int tabIndex = mOptionsTab->indexOf( renderingTab ); tabIndex >= 0 )
825 mOptionsTab->setTabToolTip( tabIndex, tr( "Rendering" ) );
826
827 mLabelingOptionsListFrame->setVisible( !enabled );
828 groupBox_mPreview->setVisible( !enabled );
829 mDockMode = enabled;
830}
831
832void QgsTextFormatWidget::connectValueChanged( const QList<QWidget *> &widgets )
833{
834 const auto constWidgets = widgets;
835 for ( QWidget *widget : constWidgets )
836 {
837 if ( QgsSymbolButton *w = qobject_cast<QgsSymbolButton *>( widget ) )
838 {
840 }
841 else if ( QgsFieldExpressionWidget *w = qobject_cast<QgsFieldExpressionWidget *>( widget ) )
842 {
843 connect( w, qOverload<const QString &>( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsTextFormatWidget::updatePreview );
844 }
845 else if ( QgsOpacityWidget *w = qobject_cast<QgsOpacityWidget *>( widget ) )
846 {
848 }
849 else if ( QgsScaleWidget *w = qobject_cast<QgsScaleWidget *>( widget ) )
850 {
852 }
853 else if ( QgsUnitSelectionWidget *w = qobject_cast<QgsUnitSelectionWidget *>( widget ) )
854 {
856 }
857 else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
858 {
859 connect( w, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsTextFormatWidget::updatePreview );
860 }
861 else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
862 {
863 connect( w, qOverload<int>( &QSpinBox::valueChanged ), this, &QgsTextFormatWidget::updatePreview );
864 }
865 else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
866 {
867 connect( w, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsTextFormatWidget::updatePreview );
868 }
869 else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
870 {
872 }
873 else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
874 {
875 connect( w, &QCheckBox::toggled, this, &QgsTextFormatWidget::updatePreview );
876 }
877 else if ( QRadioButton *w = qobject_cast<QRadioButton *>( widget ) )
878 {
879 connect( w, &QRadioButton::toggled, this, &QgsTextFormatWidget::updatePreview );
880 }
881 else if ( QLineEdit *w = qobject_cast<QLineEdit *>( widget ) )
882 {
883 connect( w, &QLineEdit::textEdited, this, &QgsTextFormatWidget::updatePreview );
884 }
885 else if ( QSlider *w = qobject_cast<QSlider *>( widget ) )
886 {
887 connect( w, &QSlider::valueChanged, this, &QgsTextFormatWidget::updatePreview );
888 }
889 else if ( QGroupBox *w = qobject_cast<QGroupBox *>( widget ) )
890 {
891 connect( w, &QGroupBox::toggled, this, &QgsTextFormatWidget::updatePreview );
892 }
893 else if ( QgsCodeEditorExpression *w = qobject_cast<QgsCodeEditorExpression *>( widget ) )
894 {
895 connect( w, &QgsCodeEditorExpression::textChanged, this, &QgsTextFormatWidget::updatePreview );
896 }
897 else
898 {
899 QgsLogger::warning( u"Could not create connection for widget %1"_s.arg( widget->objectName() ) );
900 }
901 }
902}
903
905{
906 // text style
907 registerDataDefinedButton( mFontDDBtn, QgsPalLayerSettings::Property::Family );
908 registerDataDefinedButton( mFontStyleDDBtn, QgsPalLayerSettings::Property::FontStyle );
909 registerDataDefinedButton( mFontUnderlineDDBtn, QgsPalLayerSettings::Property::Underline );
910 registerDataDefinedButton( mFontStrikeoutDDBtn, QgsPalLayerSettings::Property::Strikeout );
911 registerDataDefinedButton( mFontBoldDDBtn, QgsPalLayerSettings::Property::Bold );
912 registerDataDefinedButton( mFontItalicDDBtn, QgsPalLayerSettings::Property::Italic );
913 registerDataDefinedButton( mFontSizeDDBtn, QgsPalLayerSettings::Property::Size );
914 registerDataDefinedButton( mFontUnitsDDBtn, QgsPalLayerSettings::Property::FontSizeUnit );
915 registerDataDefinedButton( mFontColorDDBtn, QgsPalLayerSettings::Property::Color );
916 registerDataDefinedButton( mFontOpacityDDBtn, QgsPalLayerSettings::Property::FontOpacity );
917 registerDataDefinedButton( mFontCaseDDBtn, QgsPalLayerSettings::Property::FontCase );
918 registerDataDefinedButton( mFontLetterSpacingDDBtn, QgsPalLayerSettings::Property::FontLetterSpacing );
919 registerDataDefinedButton( mFontWordSpacingDDBtn, QgsPalLayerSettings::Property::FontWordSpacing );
920 registerDataDefinedButton( mFontBlendModeDDBtn, QgsPalLayerSettings::Property::FontBlendMode );
921 registerDataDefinedButton( mFontStretchDDBtn, QgsPalLayerSettings::Property::FontStretchFactor );
922 registerDataDefinedButton( mTabDistanceDDBtn, QgsPalLayerSettings::Property::TabStopDistance );
923
924 // text formatting
925 registerDataDefinedButton( mWrapCharDDBtn, QgsPalLayerSettings::Property::MultiLineWrapChar );
926 registerDataDefinedButton( mAutoWrapLengthDDBtn, QgsPalLayerSettings::Property::AutoWrapLength );
927 registerDataDefinedButton( mFontLineHeightDDBtn, QgsPalLayerSettings::Property::MultiLineHeight );
928 registerDataDefinedButton( mFontMultiLineAlignDDBtn, QgsPalLayerSettings::Property::MultiLineAlignment );
929 registerDataDefinedButton( mTextOrientationDDBtn, QgsPalLayerSettings::Property::TextOrientation );
930
931 registerDataDefinedButton( mDirectSymbDDBtn, QgsPalLayerSettings::Property::DirSymbDraw );
932 mDirectSymbDDBtn->registerCheckedWidget( mDirectSymbChkBx );
933 registerDataDefinedButton( mDirectSymbLeftDDBtn, QgsPalLayerSettings::Property::DirSymbLeft );
934 registerDataDefinedButton( mDirectSymbRightDDBtn, QgsPalLayerSettings::Property::DirSymbRight );
935
936 registerDataDefinedButton( mDirectSymbPlacementDDBtn, QgsPalLayerSettings::Property::DirSymbPlacement );
937 registerDataDefinedButton( mDirectSymbRevDDBtn, QgsPalLayerSettings::Property::DirSymbReverse );
938
939 registerDataDefinedButton( mFormatNumDDBtn, QgsPalLayerSettings::Property::NumFormat );
940 mFormatNumDDBtn->registerCheckedWidget( mFormatNumChkBx );
941 registerDataDefinedButton( mFormatNumDecimalsDDBtn, QgsPalLayerSettings::Property::NumDecimals );
942 registerDataDefinedButton( mFormatNumPlusSignDDBtn, QgsPalLayerSettings::Property::NumPlusSign );
943
944 // text buffer
945 registerDataDefinedButton( mBufferDrawDDBtn, QgsPalLayerSettings::Property::BufferDraw );
946 registerDataDefinedButton( mBufferSizeDDBtn, QgsPalLayerSettings::Property::BufferSize );
947 registerDataDefinedButton( mBufferUnitsDDBtn, QgsPalLayerSettings::Property::BufferUnit );
948 registerDataDefinedButton( mBufferColorDDBtn, QgsPalLayerSettings::Property::BufferColor );
949 registerDataDefinedButton( mBufferOpacityDDBtn, QgsPalLayerSettings::Property::BufferOpacity );
950 registerDataDefinedButton( mBufferJoinStyleDDBtn, QgsPalLayerSettings::Property::BufferJoinStyle );
951 registerDataDefinedButton( mBufferBlendModeDDBtn, QgsPalLayerSettings::Property::BufferBlendMode );
952
953 // mask
954 registerDataDefinedButton( mEnableMaskDDBtn, QgsPalLayerSettings::Property::MaskEnabled );
955 mEnableMaskDDBtn->registerCheckedWidget( mEnableMaskChkBx );
956 registerDataDefinedButton( mMaskBufferSizeDDBtn, QgsPalLayerSettings::Property::MaskBufferSize );
957 registerDataDefinedButton( mMaskBufferUnitsDDBtn, QgsPalLayerSettings::Property::MaskBufferUnit );
958 registerDataDefinedButton( mMaskOpacityDDBtn, QgsPalLayerSettings::Property::MaskOpacity );
959 registerDataDefinedButton( mMaskJoinStyleDDBtn, QgsPalLayerSettings::Property::MaskJoinStyle );
960
961 // background
962 registerDataDefinedButton( mShapeDrawDDBtn, QgsPalLayerSettings::Property::ShapeDraw );
963 mShapeDrawDDBtn->registerCheckedWidget( mShapeDrawChkBx );
964 registerDataDefinedButton( mShapeTypeDDBtn, QgsPalLayerSettings::Property::ShapeKind );
965 registerDataDefinedButton( mShapeSVGPathDDBtn, QgsPalLayerSettings::Property::ShapeSVGFile );
966 registerDataDefinedButton( mShapeSizeTypeDDBtn, QgsPalLayerSettings::Property::ShapeSizeType );
967 registerDataDefinedButton( mShapeSizeXDDBtn, QgsPalLayerSettings::Property::ShapeSizeX );
968 registerDataDefinedButton( mShapeSizeYDDBtn, QgsPalLayerSettings::Property::ShapeSizeY );
969 registerDataDefinedButton( mShapeSizeUnitsDDBtn, QgsPalLayerSettings::Property::ShapeSizeUnits );
970 registerDataDefinedButton( mShapeRotationTypeDDBtn, QgsPalLayerSettings::Property::ShapeRotationType );
971 registerDataDefinedButton( mShapeRotationDDBtn, QgsPalLayerSettings::Property::ShapeRotation );
972 registerDataDefinedButton( mShapeOffsetDDBtn, QgsPalLayerSettings::Property::ShapeOffset );
973 registerDataDefinedButton( mShapeOffsetUnitsDDBtn, QgsPalLayerSettings::Property::ShapeOffsetUnits );
974 registerDataDefinedButton( mShapeRadiusDDBtn, QgsPalLayerSettings::Property::ShapeRadii );
975 registerDataDefinedButton( mShapeRadiusUnitsDDBtn, QgsPalLayerSettings::Property::ShapeRadiiUnits );
976 registerDataDefinedButton( mShapeOpacityDDBtn, QgsPalLayerSettings::Property::ShapeOpacity );
977 registerDataDefinedButton( mShapeBlendModeDDBtn, QgsPalLayerSettings::Property::ShapeBlendMode );
978 registerDataDefinedButton( mShapeFillColorDDBtn, QgsPalLayerSettings::Property::ShapeFillColor );
979 registerDataDefinedButton( mShapeStrokeColorDDBtn, QgsPalLayerSettings::Property::ShapeStrokeColor );
980 registerDataDefinedButton( mShapeStrokeWidthDDBtn, QgsPalLayerSettings::Property::ShapeStrokeWidth );
981 registerDataDefinedButton( mShapeStrokeUnitsDDBtn, QgsPalLayerSettings::Property::ShapeStrokeWidthUnits );
982
983 // drop shadows
984 registerDataDefinedButton( mShadowDrawDDBtn, QgsPalLayerSettings::Property::ShadowDraw );
985 mShadowDrawDDBtn->registerCheckedWidget( mShadowDrawChkBx );
986 registerDataDefinedButton( mShadowUnderDDBtn, QgsPalLayerSettings::Property::ShadowUnder );
987 registerDataDefinedButton( mShadowOffsetAngleDDBtn, QgsPalLayerSettings::Property::ShadowOffsetAngle );
988 registerDataDefinedButton( mShadowOffsetDDBtn, QgsPalLayerSettings::Property::ShadowOffsetDist );
989 registerDataDefinedButton( mShadowOffsetUnitsDDBtn, QgsPalLayerSettings::Property::ShadowOffsetUnits );
990 registerDataDefinedButton( mShadowRadiusDDBtn, QgsPalLayerSettings::Property::ShadowRadius );
991 registerDataDefinedButton( mShadowRadiusUnitsDDBtn, QgsPalLayerSettings::Property::ShadowRadiusUnits );
992 registerDataDefinedButton( mShadowOpacityDDBtn, QgsPalLayerSettings::Property::ShadowOpacity );
993 registerDataDefinedButton( mShadowScaleDDBtn, QgsPalLayerSettings::Property::ShadowScale );
994 registerDataDefinedButton( mShadowColorDDBtn, QgsPalLayerSettings::Property::ShadowColor );
995 registerDataDefinedButton( mShadowBlendDDBtn, QgsPalLayerSettings::Property::ShadowBlendMode );
996
997 // placement
998 registerDataDefinedButton( mCentroidDDBtn, QgsPalLayerSettings::Property::CentroidWhole );
999 registerDataDefinedButton( mPointQuadOffsetDDBtn, QgsPalLayerSettings::Property::OffsetQuad );
1000 registerDataDefinedButton( mPointPositionOrderDDBtn, QgsPalLayerSettings::Property::PredefinedPositionOrder );
1001 registerDataDefinedButton( mLinePlacementFlagsDDBtn, QgsPalLayerSettings::Property::LinePlacementOptions );
1002 registerDataDefinedButton( mPointOffsetDDBtn, QgsPalLayerSettings::Property::OffsetXY );
1003 registerDataDefinedButton( mPointOffsetUnitsDDBtn, QgsPalLayerSettings::Property::OffsetUnits );
1004 registerDataDefinedButton( mLineDistanceDDBtn, QgsPalLayerSettings::Property::LabelDistance );
1005 registerDataDefinedButton( mLineDistanceUnitDDBtn, QgsPalLayerSettings::Property::DistanceUnits );
1006 registerDataDefinedButton( mMaximumDistanceDDBtn, QgsPalLayerSettings::Property::MaximumDistance );
1007 registerDataDefinedButton( mPriorityDDBtn, QgsPalLayerSettings::Property::Priority );
1008 registerDataDefinedButton( mAllowOutsidePolygonsDDBtn, QgsPalLayerSettings::Property::PolygonLabelOutside );
1009 registerDataDefinedButton( mAllowInferiorPlacementDBtn, QgsPalLayerSettings::Property::AllowDegradedPlacement );
1010 registerDataDefinedButton( mOverlapHandlingDBtn, QgsPalLayerSettings::Property::OverlapHandling );
1011 registerDataDefinedButton( mCurvedLabelModeDDBtn, QgsPalLayerSettings::Property::CurvedLabelMode );
1012 registerDataDefinedButton( mWhitespaceDDBtn, QgsPalLayerSettings::Property::WhitespaceCollisionHandling );
1013
1014 // TODO: is this necessary? maybe just use the data defined-only rotation?
1015 //mPointAngleDDBtn, QgsPalLayerSettings::OffsetRotation,
1016 // QgsPropertyOverrideButton::AnyType, QgsPropertyOverrideButton::double180RotDesc() );
1017 registerDataDefinedButton( mMaxCharAngleDDBtn, QgsPalLayerSettings::Property::CurvedCharAngleInOut );
1018 registerDataDefinedButton( mRepeatDistanceDDBtn, QgsPalLayerSettings::Property::RepeatDistance );
1019 registerDataDefinedButton( mRepeatDistanceUnitDDBtn, QgsPalLayerSettings::Property::RepeatDistanceUnit );
1020 registerDataDefinedButton( mOverrunDistanceDDBtn, QgsPalLayerSettings::Property::OverrunDistance );
1021
1022 registerDataDefinedButton( mLabelMarginDDBtn, QgsPalLayerSettings::Property::LabelMarginDistance );
1023
1024 // data defined-only
1025 registerDataDefinedButton( mCoordXDDBtn, QgsPalLayerSettings::Property::PositionX );
1026 registerDataDefinedButton( mCoordYDDBtn, QgsPalLayerSettings::Property::PositionY );
1027 registerDataDefinedButton( mCoordPointDDBtn, QgsPalLayerSettings::Property::PositionPoint );
1028 registerDataDefinedButton( mCoordAlignmentHDDBtn, QgsPalLayerSettings::Property::Hali );
1029 registerDataDefinedButton( mCoordAlignmentVDDBtn, QgsPalLayerSettings::Property::Vali );
1030 registerDataDefinedButton( mCoordRotationDDBtn, QgsPalLayerSettings::Property::LabelRotation );
1031
1032 updateDataDefinedAlignment();
1033
1034 // rendering
1035 const QString ddScaleVisInfo = tr(
1036 "Value &lt; 0 represents a scale closer than 1:1, e.g. -10 = 10:1<br>"
1037 "Value of 0 disables the specific limit."
1038 );
1039 registerDataDefinedButton( mScaleBasedVisibilityDDBtn, QgsPalLayerSettings::Property::ScaleVisibility );
1040 mScaleBasedVisibilityDDBtn->registerCheckedWidget( mScaleBasedVisibilityChkBx );
1041 registerDataDefinedButton( mScaleBasedVisibilityMinDDBtn, QgsPalLayerSettings::Property::MinimumScale );
1042 mScaleBasedVisibilityMinDDBtn->setUsageInfo( ddScaleVisInfo );
1043 registerDataDefinedButton( mScaleBasedVisibilityMaxDDBtn, QgsPalLayerSettings::Property::MaximumScale );
1044 mScaleBasedVisibilityMaxDDBtn->setUsageInfo( ddScaleVisInfo );
1045
1046 // use either global scales or project scales
1047 if ( QgsProject::instance()->viewSettings()->useProjectScales() )
1048 {
1049 const QVector<double> scales = QgsProject::instance()->viewSettings()->mapScales();
1050 mMinScaleWidget->setPredefinedScales( scales );
1051 mMaxScaleWidget->setPredefinedScales( scales );
1052 }
1053 else
1054 {
1055 // use global scales
1056 mMinScaleWidget->updateScales();
1057 mMaxScaleWidget->updateScales();
1058 }
1059
1060 registerDataDefinedButton( mFontLimitPixelDDBtn, QgsPalLayerSettings::Property::FontLimitPixel );
1061 mFontLimitPixelDDBtn->registerCheckedWidget( mFontLimitPixelChkBox );
1062 registerDataDefinedButton( mFontMinPixelDDBtn, QgsPalLayerSettings::Property::FontMinPixel );
1063 registerDataDefinedButton( mFontMaxPixelDDBtn, QgsPalLayerSettings::Property::FontMaxPixel );
1064
1065 registerDataDefinedButton( mShowLabelDDBtn, QgsPalLayerSettings::Property::Show );
1066
1067 registerDataDefinedButton( mAlwaysShowDDBtn, QgsPalLayerSettings::Property::AlwaysShow );
1068
1069 registerDataDefinedButton( mIsObstacleDDBtn, QgsPalLayerSettings::Property::IsObstacle );
1070 registerDataDefinedButton( mZIndexDDBtn, QgsPalLayerSettings::Property::ZIndex );
1071
1072 registerDataDefinedButton( mCalloutDrawDDBtn, QgsPalLayerSettings::Property::CalloutDraw );
1073
1074 registerDataDefinedButton( mLabelAllPartsDDBtn, QgsPalLayerSettings::Property::LabelAllParts );
1075
1076 registerDataDefinedButton( mNoDuplicatesDDBtn, QgsPalLayerSettings::Property::RemoveDuplicateLabels );
1077}
1078
1079void QgsTextFormatWidget::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsPalLayerSettings::Property key )
1080{
1081 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
1082
1083 button->init( static_cast<int>( key ), mDataDefinedProperties, QgsPalLayerSettings::propertyDefinitions(), vLayer, true );
1084 if ( !mButtons.contains( key ) )
1085 {
1086 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsTextFormatWidget::updateProperty );
1087 connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsTextFormatWidget::createAuxiliaryField );
1088 button->registerExpressionContextGenerator( this );
1089 mButtons[key] = button;
1090 }
1091}
1092
1094{
1095 const QgsTextBufferSettings buffer = format.buffer();
1096 const QgsTextMaskSettings mask = format.mask();
1097 const QgsTextBackgroundSettings background = format.background();
1098 const QgsTextShadowSettings shadow = format.shadow();
1099
1100 if ( mWidgetMode != Labeling )
1101 {
1102 mDataDefinedProperties = format.dataDefinedProperties();
1103 }
1104
1105 mTabPositions = format.tabPositions();
1106 mTabStopDistanceSpin->setEnabled( mTabPositions.empty() );
1107
1108 // buffer
1109 mBufferDrawChkBx->setChecked( buffer.enabled() );
1110 mBufferFrame->setEnabled( buffer.enabled() );
1111 spinBufferSize->setValue( buffer.size() );
1112 mBufferUnitWidget->setUnit( buffer.sizeUnit() );
1113 mBufferUnitWidget->setMapUnitScale( buffer.sizeMapUnitScale() );
1114 btnBufferColor->setColor( buffer.color() );
1115 mBufferOpacityWidget->setOpacity( buffer.opacity() );
1116 mBufferJoinStyleComboBox->setPenJoinStyle( buffer.joinStyle() );
1117 mBufferTranspFillChbx->setChecked( buffer.fillBufferInterior() );
1118 comboBufferBlendMode->setBlendMode( buffer.blendMode() );
1119 if ( auto *lPaintEffect = buffer.paintEffect() )
1120 mBufferEffect.reset( lPaintEffect->clone() );
1121 else
1122 {
1123 mBufferEffect = QgsPaintEffectRegistry::defaultStack();
1124 mBufferEffect->setEnabled( false );
1125 }
1126 mBufferEffectWidget->setPaintEffect( mBufferEffect.get() );
1127
1128 // mask
1130 mEnableMaskChkBx->setChecked( mask.enabled() );
1131 mMaskBufferSizeSpinBox->setValue( mask.size() );
1132 mMaskBufferUnitWidget->setUnit( mask.sizeUnit() );
1133 mMaskBufferUnitWidget->setMapUnitScale( mask.sizeMapUnitScale() );
1134 mMaskOpacityWidget->setOpacity( mask.opacity() );
1135 mMaskJoinStyleComboBox->setPenJoinStyle( mask.joinStyle() );
1136 if ( auto *lPaintEffect = mask.paintEffect() )
1137 mMaskEffect.reset( lPaintEffect->clone() );
1138 else
1139 {
1141 mMaskEffect->setEnabled( false );
1142 }
1143 mMaskEffectWidget->setPaintEffect( mMaskEffect.get() );
1144
1145 mFontSizeUnitWidget->setUnit( format.sizeUnit() );
1146 mFontSizeUnitWidget->setMapUnitScale( format.sizeMapUnitScale() );
1147 mRefFont = format.font();
1148 mFontSizeSpinBox->setValue( format.size() );
1149 btnTextColor->setColor( format.color() );
1150 whileBlocking( mSpinStretch )->setValue( format.stretchFactor() );
1151 mTextOpacityWidget->setOpacity( format.opacity() );
1152 comboBlendMode->setBlendMode( format.blendMode() );
1153 mTextOrientationComboBox->setCurrentIndex( mTextOrientationComboBox->findData( static_cast<int>( format.orientation() ) ) );
1154 mHtmlFormattingCheckBox->setChecked( format.allowHtmlFormatting() );
1155
1156 mFontWordSpacingSpinBox->setValue( format.font().wordSpacing() );
1157 mFontLetterSpacingSpinBox->setValue( format.font().letterSpacing() );
1158 whileBlocking( mKerningCheckBox )->setChecked( format.font().kerning() );
1159
1160 mTabDistanceUnitWidget->setUnit( format.tabStopDistanceUnit() );
1161 mTabDistanceUnitWidget->setMapUnitScale( format.tabStopDistanceMapUnitScale() );
1162 whileBlocking( mTabStopDistanceSpin )->setValue( format.tabStopDistanceUnit() == Qgis::RenderUnit::Percentage ? ( format.tabStopDistance() * 100 ) : format.tabStopDistance() );
1163
1164 whileBlocking( mFontCapitalsComboBox )->setCurrentIndex( mFontCapitalsComboBox->findData( static_cast<int>( format.capitalization() ) ) );
1165 QgsFontUtils::updateFontViaStyle( mRefFont, format.namedStyle() );
1166 updateFont( mRefFont );
1167
1168 // show 'font not found' if substitution has occurred (should come after updateFont())
1169 mFontMissingLabel->setVisible( !format.fontFound() );
1170 if ( !format.fontFound() )
1171 {
1172 const QString missingTxt = tr( "%1 not found. Default substituted." );
1173 QString txtPrepend = tr( "Chosen font" );
1174 if ( !format.resolvedFontFamily().isEmpty() )
1175 {
1176 txtPrepend = u"'%1'"_s.arg( format.resolvedFontFamily() );
1177 }
1178 mFontMissingLabel->setText( missingTxt.arg( txtPrepend ) );
1179
1180 // ensure user is sent to 'Text style' section to see notice
1181 mLabelingOptionsListWidget->setCurrentItem( mTextItem );
1182 whileBlocking( mOptionsTab )->setCurrentIndex( mOptionsTab->indexOf( textTab ) );
1183 }
1184 mFontLineHeightSpinBox->setValue( format.lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( format.lineHeight() * 100 ) : format.lineHeight() );
1185 mLineHeightUnitWidget->setUnit( format.lineHeightUnit() );
1186
1187 // shape background
1188 mShapeDrawChkBx->setChecked( background.enabled() );
1189 mShapeFrame->setEnabled( background.enabled() );
1190 mShapeTypeCmbBx->blockSignals( true );
1191 mShapeTypeCmbBx->setCurrentIndex( mShapeTypeCmbBx->findData( background.type() ) );
1192 mShapeTypeCmbBx->blockSignals( false );
1193 updateAvailableShadowPositions();
1194 mShapeSVGPathLineEdit->setText( background.svgFile() );
1195
1196 mShapeSizeCmbBx->setCurrentIndex( background.sizeType() );
1197 mShapeSizeXSpnBx->setValue( background.size().width() );
1198 mShapeSizeYSpnBx->setValue( background.size().height() );
1199 mShapeSizeUnitWidget->setUnit( background.sizeUnit() );
1200 mShapeSizeUnitWidget->setMapUnitScale( background.sizeMapUnitScale() );
1201 mShapeRotationCmbBx->setCurrentIndex( background.rotationType() );
1202 mShapeRotationDblSpnBx->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync );
1203 mShapeRotationDDBtn->setEnabled( background.rotationType() != QgsTextBackgroundSettings::RotationSync );
1204 mShapeRotationDblSpnBx->setValue( background.rotation() );
1205 mShapeOffsetXSpnBx->setValue( background.offset().x() );
1206 mShapeOffsetYSpnBx->setValue( background.offset().y() );
1207 mShapeOffsetUnitWidget->setUnit( background.offsetUnit() );
1208 mShapeOffsetUnitWidget->setMapUnitScale( background.offsetMapUnitScale() );
1209 mShapeRadiusXDbSpnBx->setValue( background.radii().width() );
1210 mShapeRadiusYDbSpnBx->setValue( background.radii().height() );
1211 mShapeRadiusUnitWidget->setUnit( background.radiiUnit() );
1212 mShapeRadiusUnitWidget->setMapUnitScale( background.radiiMapUnitScale() );
1213
1214 mShapeFillColorBtn->setColor( background.fillColor() );
1215 mShapeStrokeColorBtn->setColor( background.strokeColor() );
1216 mShapeStrokeWidthSpnBx->setValue( background.strokeWidth() );
1217 mShapeStrokeWidthUnitWidget->setUnit( background.strokeWidthUnit() );
1218 mShapeStrokeWidthUnitWidget->setMapUnitScale( background.strokeWidthMapUnitScale() );
1219
1220 mBackgroundOpacityWidget->setOpacity( background.opacity() );
1221 mShapeBlendCmbBx->setBlendMode( background.blendMode() );
1222
1223 mLoadSvgParams = false;
1224 mShapeTypeCmbBx_currentIndexChanged( background.type() ); // force update of shape background gui
1225
1226 if ( auto *lPaintEffect = background.paintEffect() )
1227 mBackgroundEffect.reset( lPaintEffect->clone() );
1228 else
1229 {
1230 mBackgroundEffect = QgsPaintEffectRegistry::defaultStack();
1231 mBackgroundEffect->setEnabled( false );
1232 }
1233 mBackgroundEffectWidget->setPaintEffect( mBackgroundEffect.get() );
1234
1235 mBackgroundMarkerSymbolButton->setSymbol( background.markerSymbol() ? background.markerSymbol()->clone() : QgsSymbol::defaultSymbol( Qgis::GeometryType::Point ).release() );
1236 mBackgroundFillSymbolButton->setSymbol( background.fillSymbol() ? background.fillSymbol()->clone() : QgsSymbol::defaultSymbol( Qgis::GeometryType::Polygon ).release() );
1237
1238 // drop shadow
1239 mShadowDrawChkBx->setChecked( shadow.enabled() );
1240 mShadowFrame->setEnabled( shadow.enabled() );
1241 mShadowUnderCmbBx->setCurrentIndex( mShadowUnderCmbBx->findData( shadow.shadowPlacement() ) );
1242 mShadowOffsetAngleSpnBx->setValue( shadow.offsetAngle() );
1243 mShadowOffsetSpnBx->setValue( shadow.offsetDistance() );
1244 mShadowOffsetUnitWidget->setUnit( shadow.offsetUnit() );
1245 mShadowOffsetUnitWidget->setMapUnitScale( shadow.offsetMapUnitScale() );
1246 mShadowOffsetGlobalChkBx->setChecked( shadow.offsetGlobal() );
1247
1248 mShadowRadiusDblSpnBx->setValue( shadow.blurRadius() );
1249 mShadowRadiusUnitWidget->setUnit( shadow.blurRadiusUnit() );
1250 mShadowRadiusUnitWidget->setMapUnitScale( shadow.blurRadiusMapUnitScale() );
1251 mShadowRadiusAlphaChkBx->setChecked( shadow.blurAlphaOnly() );
1252 mShadowOpacityWidget->setOpacity( shadow.opacity() );
1253 mShadowScaleSpnBx->setValue( shadow.scale() );
1254
1255 mShadowColorBtn->setColor( shadow.color() );
1256 mShadowBlendCmbBx->setBlendMode( shadow.blendMode() );
1257
1258 mPreviewBackgroundBtn->setColor( format.previewBackgroundColor() );
1259 mPreviewBackgroundBtn->setDefaultColor( format.previewBackgroundColor() );
1260 setPreviewBackground( format.previewBackgroundColor() );
1261
1263}
1264
1266{
1267 QgsSettings settings;
1268 settings.setValue( u"Windows/Labeling/FontPreviewSplitState"_s, mFontPreviewSplitter->saveState() );
1269 settings.setValue( u"Windows/Labeling/OptionsSplitState"_s, mLabelingOptionsSplitter->saveState() );
1270
1271 int prevIndex = mLabelingOptionsListWidget->currentRow();
1272 if ( mWidgetMode == Text )
1273 {
1274 switch ( prevIndex )
1275 {
1276 case 3: // background - account for removed mask tab
1277 case 4: // shadow - account for removed mask tab
1278 prevIndex++;
1279 break;
1280 }
1281 }
1282
1283 settings.setValue( u"Windows/Labeling/Tab"_s, prevIndex );
1284}
1285
1286QgsTextFormat QgsTextFormatWidget::format( bool includeDataDefinedProperties ) const
1287{
1289 format.setColor( btnTextColor->color() );
1290 format.setFont( mRefFont );
1291 format.setSize( mFontSizeSpinBox->value() );
1292 format.setNamedStyle( mFontStyleComboBox->currentText() );
1293 format.setOpacity( mTextOpacityWidget->opacity() );
1294 format.setStretchFactor( mSpinStretch->value() );
1295 format.setBlendMode( comboBlendMode->blendMode() );
1296 format.setSizeUnit( mFontSizeUnitWidget->unit() );
1297 format.setSizeMapUnitScale( mFontSizeUnitWidget->getMapUnitScale() );
1298 format.setLineHeight( mLineHeightUnitWidget->unit() == Qgis::RenderUnit::Percentage ? ( mFontLineHeightSpinBox->value() / 100 ) : mFontLineHeightSpinBox->value() );
1299 format.setLineHeightUnit( mLineHeightUnitWidget->unit() );
1300 format.setPreviewBackgroundColor( mPreviewBackgroundColor );
1301 format.setOrientation( static_cast<Qgis::TextOrientation>( mTextOrientationComboBox->currentData().toInt() ) );
1302 format.setAllowHtmlFormatting( mHtmlFormattingCheckBox->isChecked() );
1303 format.setCapitalization( static_cast<Qgis::Capitalization>( mFontCapitalsComboBox->currentData().toInt() ) );
1304 format.setTabStopDistance( mTabDistanceUnitWidget->unit() == Qgis::RenderUnit::Percentage ? ( mTabStopDistanceSpin->value() / 100 ) : mTabStopDistanceSpin->value() );
1305 format.setTabStopDistanceUnit( mTabDistanceUnitWidget->unit() );
1306 format.setTabStopDistanceMapUnitScale( mTabDistanceUnitWidget->getMapUnitScale() );
1307 format.setTabPositions( mTabPositions );
1308
1309 // buffer
1310 QgsTextBufferSettings buffer;
1311 buffer.setEnabled( mBufferDrawChkBx->isChecked() );
1312 buffer.setSize( spinBufferSize->value() );
1313 buffer.setColor( btnBufferColor->color() );
1314 buffer.setOpacity( mBufferOpacityWidget->opacity() );
1315 buffer.setSizeUnit( mBufferUnitWidget->unit() );
1316 buffer.setSizeMapUnitScale( mBufferUnitWidget->getMapUnitScale() );
1317 buffer.setJoinStyle( mBufferJoinStyleComboBox->penJoinStyle() );
1318 buffer.setFillBufferInterior( mBufferTranspFillChbx->isChecked() );
1319 buffer.setBlendMode( comboBufferBlendMode->blendMode() );
1320 if ( mBufferEffect && ( !QgsPaintEffectRegistry::isDefaultStack( mBufferEffect.get() ) || mBufferEffect->enabled() ) )
1321 buffer.setPaintEffect( mBufferEffect->clone() );
1322 else
1323 buffer.setPaintEffect( nullptr );
1324 format.setBuffer( buffer );
1325
1326 // mask
1328 mask.setEnabled( mEnableMaskChkBx->isChecked() );
1329 mask.setSize( mMaskBufferSizeSpinBox->value() );
1330 mask.setOpacity( mMaskOpacityWidget->opacity() );
1331 mask.setSizeUnit( mMaskBufferUnitWidget->unit() );
1332 mask.setSizeMapUnitScale( mMaskBufferUnitWidget->getMapUnitScale() );
1333 mask.setJoinStyle( mMaskJoinStyleComboBox->penJoinStyle() );
1334 if ( mMaskEffect && ( !QgsPaintEffectRegistry::isDefaultStack( mMaskEffect.get() ) || mMaskEffect->enabled() ) )
1335 mask.setPaintEffect( mMaskEffect->clone() );
1336 else
1337 mask.setPaintEffect( nullptr );
1339 format.setMask( mask );
1340
1341 // shape background
1342 QgsTextBackgroundSettings background;
1343 background.setEnabled( mShapeDrawChkBx->isChecked() );
1344 background.setType( static_cast<QgsTextBackgroundSettings::ShapeType>( mShapeTypeCmbBx->currentData().toInt() ) );
1345 background.setSvgFile( mShapeSVGPathLineEdit->text() );
1346 background.setSizeType( static_cast<QgsTextBackgroundSettings::SizeType>( mShapeSizeCmbBx->currentIndex() ) );
1347 background.setSize( QSizeF( mShapeSizeXSpnBx->value(), mShapeSizeYSpnBx->value() ) );
1348 background.setSizeUnit( mShapeSizeUnitWidget->unit() );
1349 background.setSizeMapUnitScale( mShapeSizeUnitWidget->getMapUnitScale() );
1350 background.setRotationType( static_cast<QgsTextBackgroundSettings::RotationType>( mShapeRotationCmbBx->currentIndex() ) );
1351 background.setRotation( mShapeRotationDblSpnBx->value() );
1352 background.setOffset( QPointF( mShapeOffsetXSpnBx->value(), mShapeOffsetYSpnBx->value() ) );
1353 background.setOffsetUnit( mShapeOffsetUnitWidget->unit() );
1354 background.setOffsetMapUnitScale( mShapeOffsetUnitWidget->getMapUnitScale() );
1355 background.setRadii( QSizeF( mShapeRadiusXDbSpnBx->value(), mShapeRadiusYDbSpnBx->value() ) );
1356 background.setRadiiUnit( mShapeRadiusUnitWidget->unit() );
1357 background.setRadiiMapUnitScale( mShapeRadiusUnitWidget->getMapUnitScale() );
1358
1359 background.setFillColor( mShapeFillColorBtn->color() );
1360 background.setStrokeColor( mShapeStrokeColorBtn->color() );
1361 background.setStrokeWidth( mShapeStrokeWidthSpnBx->value() );
1362 background.setStrokeWidthUnit( mShapeStrokeWidthUnitWidget->unit() );
1363 background.setStrokeWidthMapUnitScale( mShapeStrokeWidthUnitWidget->getMapUnitScale() );
1364 background.setOpacity( mBackgroundOpacityWidget->opacity() );
1365 background.setBlendMode( mShapeBlendCmbBx->blendMode() );
1366 if ( mBackgroundEffect && ( !QgsPaintEffectRegistry::isDefaultStack( mBackgroundEffect.get() ) || mBackgroundEffect->enabled() ) )
1367 background.setPaintEffect( mBackgroundEffect->clone() );
1368 else
1369 background.setPaintEffect( nullptr );
1370 background.setMarkerSymbol( mBackgroundMarkerSymbolButton->clonedSymbol<QgsMarkerSymbol>() );
1371 background.setFillSymbol( mBackgroundFillSymbolButton->clonedSymbol<QgsFillSymbol>() );
1372 format.setBackground( background );
1373
1374 // drop shadow
1375 QgsTextShadowSettings shadow;
1376 shadow.setEnabled( mShadowDrawChkBx->isChecked() );
1377 shadow.setShadowPlacement( static_cast<QgsTextShadowSettings::ShadowPlacement>( mShadowUnderCmbBx->currentData().toInt() ) );
1378 shadow.setOffsetAngle( mShadowOffsetAngleSpnBx->value() );
1379 shadow.setOffsetDistance( mShadowOffsetSpnBx->value() );
1380 shadow.setOffsetUnit( mShadowOffsetUnitWidget->unit() );
1381 shadow.setOffsetMapUnitScale( mShadowOffsetUnitWidget->getMapUnitScale() );
1382 shadow.setOffsetGlobal( mShadowOffsetGlobalChkBx->isChecked() );
1383 shadow.setBlurRadius( mShadowRadiusDblSpnBx->value() );
1384 shadow.setBlurRadiusUnit( mShadowRadiusUnitWidget->unit() );
1385 shadow.setBlurRadiusMapUnitScale( mShadowRadiusUnitWidget->getMapUnitScale() );
1386 shadow.setBlurAlphaOnly( mShadowRadiusAlphaChkBx->isChecked() );
1387 shadow.setOpacity( mShadowOpacityWidget->opacity() );
1388 shadow.setScale( mShadowScaleSpnBx->value() );
1389 shadow.setColor( mShadowColorBtn->color() );
1390 shadow.setBlendMode( mShadowBlendCmbBx->blendMode() );
1391 format.setShadow( shadow );
1392
1393 if ( includeDataDefinedProperties )
1394 format.setDataDefinedProperties( mDataDefinedProperties );
1395
1396 return format;
1397}
1398
1400{
1401 if ( mWidgetMode != Labeling )
1402 {
1403 // we need to combine any data defined properties from the text format with existing ones from the label settings
1404 const QgsPropertyCollection formatProps = format.dataDefinedProperties();
1405 for ( const int key : formatProps.propertyKeys() )
1406 {
1407 if ( formatProps.isActive( key ) )
1408 {
1409 mDataDefinedProperties.setProperty( key, formatProps.property( key ) );
1410 }
1411 }
1412 }
1413
1415}
1416
1421
1423{
1424 if ( mButtons.contains( key ) )
1425 {
1426 QgsPropertyOverrideButton *button = mButtons[key];
1427 button->updateFieldLists();
1428 button->setToProperty( QgsProperty() );
1429 mDataDefinedProperties.setProperty( key, QgsProperty() );
1430 }
1431}
1432
1433void QgsTextFormatWidget::optionsStackedWidget_CurrentChanged( int )
1434{
1435 mLabelingOptionsListWidget->blockSignals( true );
1436 QWidget *currentPage = mLabelStackedWidget->currentWidget();
1437 if ( currentPage == mLabelPage_Text )
1438 mLabelingOptionsListWidget->setCurrentItem( mTextItem );
1439 else if ( currentPage == mLabelPage_Formatting )
1440 mLabelingOptionsListWidget->setCurrentItem( mFormattingItem );
1441 else if ( currentPage == mLabelPage_Mask )
1442 mLabelingOptionsListWidget->setCurrentItem( mMaskItem );
1443 if ( currentPage == mLabelPage_Buffer )
1444 mLabelingOptionsListWidget->setCurrentItem( mBufferItem );
1445 if ( currentPage == mLabelPage_Background )
1446 mLabelingOptionsListWidget->setCurrentItem( mBackgroundItem );
1447 if ( currentPage == mLabelPage_Shadow )
1448 mLabelingOptionsListWidget->setCurrentItem( mShadowItem );
1449 if ( currentPage == mLabelPage_Callouts )
1450 mLabelingOptionsListWidget->setCurrentItem( mCalloutItem );
1451 if ( currentPage == mLabelPage_Rendering )
1452 mLabelingOptionsListWidget->setCurrentItem( mRenderingItem );
1453 if ( currentPage == mLabelPage_Placement )
1454 mLabelingOptionsListWidget->setCurrentItem( mPlacementItem );
1455 mLabelingOptionsListWidget->blockSignals( false );
1456}
1457
1459{
1460 mContext = context;
1461
1462 if ( auto *lExpressionContext = mContext.expressionContext() )
1463 {
1464 mPreviewExpressionContext = *lExpressionContext;
1465 if ( mLayer )
1466 mPreviewExpressionContext.appendScope( QgsExpressionContextUtils::layerScope( mLayer ) );
1467 }
1468
1469 const auto symbolButtonWidgets = findChildren<QgsSymbolButton *>();
1470 for ( QgsSymbolButton *symbolWidget : symbolButtonWidgets )
1471 {
1472 symbolWidget->setMapCanvas( mContext.mapCanvas() );
1473 symbolWidget->setMessageBar( mContext.messageBar() );
1474 }
1475}
1476
1477void QgsTextFormatWidget::collapseSample( bool collapse )
1478{
1479 if ( collapse )
1480 {
1481 QList<int> splitSizes = mFontPreviewSplitter->sizes();
1482 if ( splitSizes[0] > groupBox_mPreview->height() )
1483 {
1484 const int delta = splitSizes[0] - groupBox_mPreview->height();
1485 splitSizes[0] -= delta;
1486 splitSizes[1] += delta;
1487 mFontPreviewSplitter->setSizes( splitSizes );
1488 }
1489 }
1490}
1491
1492void QgsTextFormatWidget::changeTextColor( const QColor &color )
1493{
1494 Q_UNUSED( color )
1495 updatePreview();
1496}
1497
1498void QgsTextFormatWidget::updateFont( const QFont &newFont )
1499{
1500 // update background reference font
1501 if ( newFont != mRefFont )
1502 {
1503 mRefFont = newFont;
1504 }
1505
1506 // test if font is actually available
1507 // NOTE: QgsFontUtils::fontMatchOnSystem may fail here, just crosscheck family
1508 mFontMissingLabel->setVisible( !QgsFontUtils::fontFamilyMatchOnSystem( mRefFont.family() ) );
1509
1510 QFont symbolFont = mRefFont;
1511 symbolFont.setPointSize( font().pointSize() );
1512 mDirectSymbLeftLineEdit->setFont( symbolFont );
1513 mDirectSymbRightLineEdit->setFont( symbolFont );
1514
1515 blockFontChangeSignals( true );
1516 mFontFamilyCmbBx->setCurrentFont( symbolFont );
1517 populateFontStyleComboBox();
1518 mFontUnderlineBtn->setChecked( mRefFont.underline() );
1519 mFontStrikethroughBtn->setChecked( mRefFont.strikeOut() );
1520 mKerningCheckBox->setChecked( mRefFont.kerning() );
1521 blockFontChangeSignals( false );
1522
1523 // update font name with font face
1524 // font.setPixelSize( 24 );
1525
1526 updatePreview();
1527}
1528
1529void QgsTextFormatWidget::blockFontChangeSignals( bool blk )
1530{
1531 mFontFamilyCmbBx->blockSignals( blk );
1532 mFontStyleComboBox->blockSignals( blk );
1533 mFontCapitalsComboBox->blockSignals( blk );
1534 mFontUnderlineBtn->blockSignals( blk );
1535 mFontStrikethroughBtn->blockSignals( blk );
1536 mFontWordSpacingSpinBox->blockSignals( blk );
1537 mFontLetterSpacingSpinBox->blockSignals( blk );
1538 mKerningCheckBox->blockSignals( blk );
1539}
1540
1542{
1543 // In dock mode we don't have a preview we
1544 // just let stuff know we have changed because
1545 // there might be live updates connected.
1546 if ( mDockMode )
1547 {
1548 emit widgetChanged();
1549 return;
1550 }
1551
1552 scrollPreview();
1553 lblFontPreview->setFormat( format() );
1554}
1555
1556void QgsTextFormatWidget::scrollPreview()
1557{
1558 scrollArea_mPreview->ensureVisible( 0, 0, 0, 0 );
1559}
1560
1562{
1563 mPreviewBackgroundColor = color;
1564
1565 scrollArea_mPreview->widget()->setStyleSheet( u"background: rgb(%1, %2, %3);"_s.arg( QString::number( color.red() ), QString::number( color.green() ), QString::number( color.blue() ) ) );
1566}
1567
1568void QgsTextFormatWidget::changeBufferColor( const QColor &color )
1569{
1570 Q_UNUSED( color )
1571 updatePreview();
1572}
1573
1575{
1576 const Qgis::GeometryType currentGeometryType = labelGeometryType();
1577 bool showLineFrame = false;
1578 bool showCentroidFrame = false;
1579 bool showQuadrantFrame = false;
1580 bool showFixedQuadrantFrame = false;
1581 bool showPlacementPriorityFrame = false;
1582 bool showOffsetTypeFrame = false;
1583 bool showOffsetFrame = false;
1584 bool showDistanceFrame = false;
1585 bool showMaximumDistanceFrame = false;
1586 bool showPrioritizationFrame = false;
1587 bool showRotationFrame = false;
1588 bool showMaxCharAngleFrame = false;
1589 bool showCurvedLabelModeFrame = false;
1590 bool showWhitespaceCollisionFrame = false;
1591
1592 const Qgis::LabelPlacement currentPlacement = static_cast<Qgis::LabelPlacement>( mPlacementModeComboBox->currentData().toInt() );
1593 const bool showPolygonPlacementOptions
1594 = ( currentGeometryType == Qgis::GeometryType::Polygon && currentPlacement != Qgis::LabelPlacement::Line && currentPlacement != Qgis::LabelPlacement::PerimeterCurved && currentPlacement != Qgis::LabelPlacement::OutsidePolygons );
1595
1596 bool enableMultiLinesFrame = true;
1597
1598 if ( currentPlacement == Qgis::LabelPlacement::AroundPoint && ( currentGeometryType == Qgis::GeometryType::Point || currentGeometryType == Qgis::GeometryType::Polygon ) )
1599 {
1600 showCentroidFrame = currentGeometryType == Qgis::GeometryType::Polygon;
1601 showDistanceFrame = true;
1602 mPlacementDistanceFrame->setEnabled( true );
1603 showMaximumDistanceFrame = true;
1604 //showRotationFrame = true; // TODO: uncomment when supported
1605 showQuadrantFrame = currentGeometryType == Qgis::GeometryType::Point;
1606 }
1607 else if ( currentPlacement == Qgis::LabelPlacement::OverPoint && ( currentGeometryType == Qgis::GeometryType::Point || currentGeometryType == Qgis::GeometryType::Polygon ) )
1608 {
1609 showCentroidFrame = currentGeometryType == Qgis::GeometryType::Polygon;
1610 showQuadrantFrame = true;
1611 showFixedQuadrantFrame = true;
1612 showOffsetFrame = true;
1613 showRotationFrame = true;
1614 }
1615 else if ( currentGeometryType == Qgis::GeometryType::Point && currentPlacement == Qgis::LabelPlacement::OrderedPositionsAroundPoint )
1616 {
1617 showDistanceFrame = true;
1618 showMaximumDistanceFrame = true;
1619 showPlacementPriorityFrame = true;
1620 showPrioritizationFrame = true;
1621 showOffsetTypeFrame = true;
1622 }
1623 else if ( ( currentGeometryType == Qgis::GeometryType::Line && currentPlacement == Qgis::LabelPlacement::Line )
1624 || ( currentGeometryType == Qgis::GeometryType::Polygon && currentPlacement == Qgis::LabelPlacement::Line )
1625 || ( currentGeometryType == Qgis::GeometryType::Line && currentPlacement == Qgis::LabelPlacement::Curved )
1626 || ( currentGeometryType == Qgis::GeometryType::Polygon && currentPlacement == Qgis::LabelPlacement::PerimeterCurved ) )
1627 {
1628 showLineFrame = true;
1629 showDistanceFrame = true;
1630 showCurvedLabelModeFrame = currentPlacement == Qgis::LabelPlacement::Curved || currentPlacement == Qgis::LabelPlacement::PerimeterCurved;
1631 showWhitespaceCollisionFrame = currentPlacement == Qgis::LabelPlacement::Curved || currentPlacement == Qgis::LabelPlacement::PerimeterCurved;
1632 //showRotationFrame = true; // TODO: uncomment when supported
1633
1634 const bool offline = chkLineAbove->isChecked() || chkLineBelow->isChecked();
1635 chkLineOrientationDependent->setEnabled( offline );
1636 mPlacementDistanceFrame->setEnabled( offline );
1637
1638 const bool isCurved = ( currentGeometryType == Qgis::GeometryType::Line && currentPlacement == Qgis::LabelPlacement::Curved )
1639 || ( currentGeometryType == Qgis::GeometryType::Polygon && currentPlacement == Qgis::LabelPlacement::PerimeterCurved );
1640 showMaxCharAngleFrame = isCurved;
1641 // TODO: enable mMultiLinesFrame when supported for curved labels
1642 enableMultiLinesFrame = !isCurved;
1643 }
1644 else if ( currentGeometryType == Qgis::GeometryType::Polygon
1645 && ( currentPlacement == Qgis::LabelPlacement::OutsidePolygons || mCheckAllowLabelsOutsidePolygons->isChecked() || mAllowOutsidePolygonsDDBtn->isActive() ) )
1646 {
1647 showDistanceFrame = true;
1648 mPlacementDistanceFrame->setEnabled( true );
1649 }
1650 else if ( currentGeometryType == Qgis::GeometryType::Line && currentPlacement == Qgis::LabelPlacement::Horizontal )
1651 {
1652 showRotationFrame = true;
1653 }
1654
1655 mPlacementLineFrame->setVisible( showLineFrame );
1656 mPlacementPolygonFrame->setVisible( showPolygonPlacementOptions );
1657 mPlacementCentroidFrame->setVisible( showCentroidFrame );
1658 mPlacementQuadrantFrame->setVisible( showQuadrantFrame );
1659 mPlacementFixedQuadrantFrame->setVisible( showFixedQuadrantFrame );
1660 mPlacementCartographicFrame->setVisible( showPlacementPriorityFrame );
1661 mPlacementOffsetFrame->setVisible( showOffsetFrame );
1662 mPlacementDistanceFrame->setVisible( showDistanceFrame );
1663 mPlacementMaximumDistanceFrame->setVisible( showMaximumDistanceFrame );
1664 mPlacementPrioritizationFrame->setVisible( showPrioritizationFrame );
1665 mPlacementOffsetTypeFrame->setVisible( showOffsetTypeFrame );
1666 mWhitespaceCollisionFrame->setVisible( showWhitespaceCollisionFrame );
1667 mPlacementRotationFrame->setVisible( showRotationFrame );
1668 mPlacementRepeatGroupBox->setVisible(
1669 currentGeometryType == Qgis::GeometryType::Line
1670 || ( currentGeometryType == Qgis::GeometryType::Polygon && ( currentPlacement == Qgis::LabelPlacement::Line || currentPlacement == Qgis::LabelPlacement::PerimeterCurved ) )
1671 );
1672 mPlacementOverrunGroupBox->setVisible( currentGeometryType == Qgis::GeometryType::Line && currentPlacement != Qgis::LabelPlacement::Horizontal );
1673 mLineAnchorGroupBox->setVisible( currentGeometryType == Qgis::GeometryType::Line || currentPlacement == Qgis::LabelPlacement::Line || currentPlacement == Qgis::LabelPlacement::PerimeterCurved );
1674 mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame );
1675 mCurvedLabelModeFrame->setVisible( showCurvedLabelModeFrame );
1676
1677 mMultiLinesFrame->setEnabled( enableMultiLinesFrame );
1678
1679
1680 QString helperText;
1681 switch ( currentPlacement )
1682 {
1684 if ( currentGeometryType == Qgis::GeometryType::Point )
1685 helperText = tr( "Arranges label candidates in a clockwise circle around the feature, preferring placements to the top-right of the feature." );
1686 else if ( currentGeometryType == Qgis::GeometryType::Polygon )
1687 helperText = tr( "Arranges label candidates in a cluster around the feature's centroid, preferring placements directly over the centroid." );
1688 break;
1690 if ( currentGeometryType == Qgis::GeometryType::Point )
1691 helperText = tr( "Arranges label candidates directly over the feature or at a preset offset from the feature." );
1692 else if ( currentGeometryType == Qgis::GeometryType::Polygon )
1693 helperText = tr( "Arranges label candidates directly over the feature's centroid, or at a preset offset from the centroid." );
1694 break;
1696 if ( currentGeometryType == Qgis::GeometryType::Line )
1697 helperText = tr( "Arranges label candidates parallel to a generalised line representing the feature. Placements which fall over straighter portions of the line are preferred." );
1698 else if ( currentGeometryType == Qgis::GeometryType::Polygon )
1699 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." );
1700 break;
1702 if ( currentGeometryType == Qgis::GeometryType::Line )
1703 helperText = tr( "Arranges candidates following the curvature of a line feature. Placements which fall over straighter portions of the line are preferred." );
1704 break;
1706 if ( currentGeometryType == Qgis::GeometryType::Polygon )
1707 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." );
1708 else if ( currentGeometryType == Qgis::GeometryType::Line )
1709 helperText = tr( "Label candidates are arranged horizontally along the length of the feature." );
1710 break;
1712 if ( currentGeometryType == Qgis::GeometryType::Polygon )
1713 helperText = tr(
1714 "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."
1715 );
1716 break;
1718 if ( currentGeometryType == Qgis::GeometryType::Point )
1719 helperText
1720 = 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." );
1721 break;
1723 if ( currentGeometryType == Qgis::GeometryType::Polygon )
1724 helperText = tr( "Arranges candidates following the curvature of the feature's perimeter. Placements which fall over straighter portions of the perimeter are preferred." );
1725 break;
1727 if ( currentGeometryType == Qgis::GeometryType::Polygon )
1728 helperText = tr( "Label candidates are placed outside of the features, preferring placements which give greatest visual association between the label and the feature." );
1729 break;
1730 }
1731 mPlacementModeDescriptionLabel->setText( u"<i>%1</i>"_s.arg( helperText ) );
1732}
1733
1734void QgsTextFormatWidget::populateFontCapitalsComboBox()
1735{
1736 mFontCapitalsComboBox->addItem( tr( "No Change" ), static_cast<int>( Qgis::Capitalization::MixedCase ) );
1737 mFontCapitalsComboBox->addItem( tr( "All Uppercase" ), static_cast<int>( Qgis::Capitalization::AllUppercase ) );
1738 mFontCapitalsComboBox->addItem( tr( "All Lowercase" ), static_cast<int>( Qgis::Capitalization::AllLowercase ) );
1739 mFontCapitalsComboBox->addItem( tr( "Small Caps" ), static_cast<int>( Qgis::Capitalization::SmallCaps ) );
1740 mFontCapitalsComboBox->addItem( tr( "All Small Caps" ), static_cast<int>( Qgis::Capitalization::AllSmallCaps ) );
1741 mFontCapitalsComboBox->addItem( tr( "Title Case" ), static_cast<int>( Qgis::Capitalization::TitleCase ) );
1742 mFontCapitalsComboBox->addItem( tr( "Force First Letter to Capital" ), static_cast<int>( Qgis::Capitalization::ForceFirstLetterToCapital ) );
1743}
1744
1745void QgsTextFormatWidget::populateFontStyleComboBox()
1746{
1747 mFontStyleComboBox->clear();
1748 const QStringList styles = mFontDB.styles( mRefFont.family() );
1749 const auto constStyles = styles;
1750 for ( const QString &style : constStyles )
1751 {
1752 mFontStyleComboBox->addItem( style );
1753 }
1754
1755 QString targetStyle = mFontDB.styleString( mRefFont );
1756 if ( !styles.contains( targetStyle ) )
1757 {
1758 const QFont f = QgsFontUtils::createFont( mRefFont.family() );
1759 targetStyle = QFontInfo( f ).styleName();
1760 mRefFont.setStyleName( targetStyle );
1761 }
1762 int curIndx = 0;
1763 const int stylIndx = mFontStyleComboBox->findText( targetStyle );
1764 if ( stylIndx > -1 )
1765 {
1766 curIndx = stylIndx;
1767 }
1768
1769 mFontStyleComboBox->setCurrentIndex( curIndx );
1770}
1771
1772void QgsTextFormatWidget::mFontSizeSpinBox_valueChanged( double d )
1773{
1774 mRefFont.setPointSizeF( d );
1775 updateFont( mRefFont );
1776}
1777
1778void QgsTextFormatWidget::mFontFamilyCmbBx_currentFontChanged( const QFont &f )
1779{
1780 QgsFontUtils::setFontFamily( mRefFont, f.family() );
1781 updateFont( mRefFont );
1782}
1783
1784void QgsTextFormatWidget::mFontStyleComboBox_currentIndexChanged( const QString &text )
1785{
1786 QgsFontUtils::updateFontViaStyle( mRefFont, text );
1787 updateFont( mRefFont );
1788}
1789
1790void QgsTextFormatWidget::mFontUnderlineBtn_toggled( bool ckd )
1791{
1792 mRefFont.setUnderline( ckd );
1793 updateFont( mRefFont );
1794}
1795
1796void QgsTextFormatWidget::mFontStrikethroughBtn_toggled( bool ckd )
1797{
1798 mRefFont.setStrikeOut( ckd );
1799 updateFont( mRefFont );
1800}
1801
1802void QgsTextFormatWidget::kerningToggled( bool checked )
1803{
1804 mRefFont.setKerning( checked );
1805 updateFont( mRefFont );
1806}
1807
1808void QgsTextFormatWidget::mFontWordSpacingSpinBox_valueChanged( double spacing )
1809{
1810 mRefFont.setWordSpacing( spacing );
1811 updateFont( mRefFont );
1812}
1813
1814void QgsTextFormatWidget::mFontLetterSpacingSpinBox_valueChanged( double spacing )
1815{
1816 mRefFont.setLetterSpacing( QFont::AbsoluteSpacing, spacing );
1817 updateFont( mRefFont );
1818}
1819
1820void QgsTextFormatWidget::mFontSizeUnitWidget_changed()
1821{
1822 // disable pixel size limiting for labels defined in points
1823 if ( mFontSizeUnitWidget->unit() != Qgis::RenderUnit::MapUnits )
1824 {
1825 mFontLimitPixelChkBox->setChecked( false );
1826 }
1827 else if ( mMinPixelLimit == 0 )
1828 {
1829 // initial minimum trigger value set, turn on pixel size limiting by default
1830 // for labels defined in map units (ignored after first settings save)
1831 mFontLimitPixelChkBox->setChecked( true );
1832 }
1833 updateFont( mRefFont );
1834}
1835
1836void QgsTextFormatWidget::mFontMinPixelSpinBox_valueChanged( int px )
1837{
1838 // ensure max font pixel size for map unit labels can't be lower than min
1839 mFontMaxPixelSpinBox->setMinimum( px );
1840 mFontMaxPixelSpinBox->update();
1841}
1842
1843void QgsTextFormatWidget::mFontMaxPixelSpinBox_valueChanged( int px )
1844{
1845 // ensure max font pixel size for map unit labels can't be lower than min
1846 if ( px < mFontMinPixelSpinBox->value() )
1847 {
1848 mFontMaxPixelSpinBox->blockSignals( true );
1849 mFontMaxPixelSpinBox->setValue( mFontMinPixelSpinBox->value() );
1850 mFontMaxPixelSpinBox->blockSignals( false );
1851 }
1852 mFontMaxPixelSpinBox->setMinimum( mFontMinPixelSpinBox->value() );
1853}
1854
1855void QgsTextFormatWidget::mBufferUnitWidget_changed()
1856{
1857 updateFont( mRefFont );
1858}
1859
1860void QgsTextFormatWidget::mMaskBufferUnitWidget_changed()
1861{
1862 updateFont( mRefFont );
1863}
1864
1865void QgsTextFormatWidget::mCoordXDDBtn_changed()
1866{
1867 updateDataDefinedAlignment();
1868}
1869
1870void QgsTextFormatWidget::mCoordXDDBtn_activated( bool isActive )
1871{
1872 if ( !isActive )
1873 return;
1874
1875 mCoordPointDDBtn->setActive( false );
1876}
1877
1878void QgsTextFormatWidget::mCoordYDDBtn_changed()
1879{
1880 updateDataDefinedAlignment();
1881}
1882
1883void QgsTextFormatWidget::mCoordYDDBtn_activated( bool isActive )
1884{
1885 if ( !isActive )
1886 return;
1887
1888 mCoordPointDDBtn->setActive( false );
1889}
1890
1891void QgsTextFormatWidget::mCoordPointDDBtn_changed()
1892{
1893 updateDataDefinedAlignment();
1894}
1895
1896void QgsTextFormatWidget::mCoordPointDDBtn_activated( bool isActive )
1897{
1898 if ( !isActive )
1899 return;
1900
1901 mCoordXDDBtn->setActive( false );
1902 mCoordYDDBtn->setActive( false );
1903}
1904
1905void QgsTextFormatWidget::mShapeTypeCmbBx_currentIndexChanged( int )
1906{
1907 // shape background
1908 const QgsTextBackgroundSettings::ShapeType type = static_cast<QgsTextBackgroundSettings::ShapeType>( mShapeTypeCmbBx->currentData().toInt() );
1910 const bool isSVG = type == QgsTextBackgroundSettings::ShapeSVG;
1911 const bool isMarker = type == QgsTextBackgroundSettings::ShapeMarkerSymbol;
1912
1913 showBackgroundRadius( isRect );
1914
1915 mShapeSVGPathFrame->setVisible( isSVG );
1916 mBackgroundMarkerSymbolButton->setVisible( isMarker );
1917 mBackgroundFillSymbolButton->setVisible( !isSVG && !isMarker );
1918
1919 // symbology SVG and marker renderers only support size^2 scaling,
1920 // so we only use the x size spinbox
1921 mShapeSizeYLabel->setVisible( !isSVG && !isMarker );
1922 mShapeSizeYSpnBx->setVisible( !isSVG && !isMarker );
1923 mShapeSizeYDDBtn->setVisible( !isSVG && !isMarker );
1924 mShapeSizeXLabel->setText( tr( "Size%1" ).arg( !isSVG && !isMarker ? tr( " X" ) : QString() ) );
1925
1926 // SVG parameter setting doesn't support color's alpha component yet
1927 mShapeFillColorBtn->setAllowOpacity( !isSVG );
1928 mShapeFillColorBtn->setButtonBackground();
1929 mShapeStrokeColorBtn->setAllowOpacity( !isSVG );
1930 mShapeStrokeColorBtn->setButtonBackground();
1931
1932 // Hide parameter widgets not used by marker symbol
1933 mShapeFillColorLabel->setVisible( isSVG );
1934 mShapeFillColorLabel->setEnabled( isSVG );
1935 mShapeFillColorBtn->setVisible( isSVG );
1936 mShapeFillColorBtn->setEnabled( isSVG );
1937 mShapeFillColorDDBtn->setVisible( isSVG );
1938 mShapeFillColorDDBtn->setEnabled( isSVG );
1939 mShapeStrokeColorLabel->setVisible( isSVG );
1940 mShapeStrokeColorLabel->setEnabled( isSVG );
1941 mShapeStrokeColorBtn->setVisible( isSVG );
1942 mShapeStrokeColorBtn->setEnabled( isSVG );
1943 mShapeStrokeColorDDBtn->setVisible( isSVG );
1944 mShapeStrokeColorDDBtn->setEnabled( isSVG );
1945 mShapeStrokeWidthLabel->setVisible( isSVG );
1946 mShapeStrokeWidthLabel->setEnabled( isSVG );
1947 mShapeStrokeWidthSpnBx->setVisible( isSVG );
1948 mShapeStrokeWidthSpnBx->setEnabled( isSVG );
1949 mShapeStrokeWidthDDBtn->setVisible( isSVG );
1950 mShapeStrokeWidthDDBtn->setEnabled( isSVG );
1951
1952 // configure SVG parameter widgets
1953 mShapeSVGParamsBtn->setVisible( isSVG );
1954 if ( isSVG )
1955 {
1956 updateSvgWidgets( mShapeSVGPathLineEdit->text() );
1957 }
1958 // TODO: fix overriding SVG symbol's stroke width units in QgsSvgCache
1959 // currently broken, fall back to symbol units only
1960 mShapeSVGUnitsLabel->setVisible( isSVG );
1961 mShapeStrokeWidthUnitWidget->setVisible( false );
1962 mShapeStrokeUnitsDDBtn->setVisible( false );
1963 mShapeStrokeUnitsDDBtn->setEnabled( false );
1964
1965 updateAvailableShadowPositions();
1966}
1967
1968void QgsTextFormatWidget::mShapeSVGPathLineEdit_textChanged( const QString &text )
1969{
1970 updateSvgWidgets( text );
1971}
1972
1974{
1975 const int numOptionsChecked = ( chkLineAbove->isChecked() ? 1 : 0 ) + ( chkLineBelow->isChecked() ? 1 : 0 ) + ( chkLineOn->isChecked() ? 1 : 0 );
1976
1977 if ( numOptionsChecked == 1 )
1978 {
1979 //prevent unchecking last option
1980 chkLineAbove->setEnabled( !chkLineAbove->isChecked() );
1981 chkLineBelow->setEnabled( !chkLineBelow->isChecked() );
1982 chkLineOn->setEnabled( !chkLineOn->isChecked() );
1983 }
1984 else
1985 {
1986 chkLineAbove->setEnabled( true );
1987 chkLineBelow->setEnabled( true );
1988 chkLineOn->setEnabled( true );
1989 }
1990}
1991
1992void QgsTextFormatWidget::onSubstitutionsChanged( const QgsStringReplacementCollection &substitutions )
1993{
1994 mSubstitutions = substitutions;
1995 emit widgetChanged();
1996}
1997
1998void QgsTextFormatWidget::previewScaleChanged( double scale )
1999{
2000 lblFontPreview->setScale( scale );
2001}
2002
2003void QgsTextFormatWidget::updateSvgWidgets( const QString &svgPath )
2004{
2005 if ( mShapeSVGPathLineEdit->text() != svgPath )
2006 {
2007 mShapeSVGPathLineEdit->setText( svgPath );
2008 }
2009
2010 QString resolvedPath;
2011 bool validSVG = true;
2012 if ( !svgPath.startsWith( "base64:"_L1, Qt::CaseInsensitive ) )
2013 {
2014 resolvedPath = QgsSymbolLayerUtils::svgSymbolNameToPath( svgPath, QgsProject::instance()->pathResolver() );
2015 validSVG = QFileInfo::exists( resolvedPath );
2016 }
2017 else
2018 {
2019 resolvedPath = svgPath;
2020 validSVG = true;
2021 }
2022
2023 // draw red text for path field if invalid (path can't be resolved)
2024 mShapeSVGPathLineEdit->setStyleSheet( !validSVG ? u"QLineEdit{ color: rgb(225, 0, 0); }"_s : QString() );
2025 mShapeSVGPathLineEdit->setToolTip( !validSVG ? tr( "File not found" ) : resolvedPath );
2026
2027 QColor fill, stroke;
2028 double strokeWidth = 0.0;
2029 bool fillParam = false, strokeParam = false, strokeWidthParam = false;
2030 if ( validSVG )
2031 {
2032 QgsApplication::svgCache()->containsParams( resolvedPath, fillParam, fill, strokeParam, stroke, strokeWidthParam, strokeWidth );
2033 }
2034
2035 mShapeSVGParamsBtn->setEnabled( validSVG && ( fillParam || strokeParam || strokeWidthParam ) );
2036
2037 mShapeFillColorLabel->setEnabled( validSVG && fillParam );
2038 mShapeFillColorBtn->setEnabled( validSVG && fillParam );
2039 mShapeFillColorDDBtn->setEnabled( validSVG && fillParam );
2040 if ( mLoadSvgParams && validSVG && fillParam )
2041 mShapeFillColorBtn->setColor( fill );
2042
2043 mShapeStrokeColorLabel->setEnabled( validSVG && strokeParam );
2044 mShapeStrokeColorBtn->setEnabled( validSVG && strokeParam );
2045 mShapeStrokeColorDDBtn->setEnabled( validSVG && strokeParam );
2046 if ( mLoadSvgParams && validSVG && strokeParam )
2047 mShapeStrokeColorBtn->setColor( stroke );
2048
2049 mShapeStrokeWidthLabel->setEnabled( validSVG && strokeWidthParam );
2050 mShapeStrokeWidthSpnBx->setEnabled( validSVG && strokeWidthParam );
2051 mShapeStrokeWidthDDBtn->setEnabled( validSVG && strokeWidthParam );
2052 if ( mLoadSvgParams && validSVG && strokeWidthParam )
2053 mShapeStrokeWidthSpnBx->setValue( strokeWidth );
2054
2055 // TODO: fix overriding SVG symbol's stroke width units in QgsSvgCache
2056 // currently broken, fall back to symbol's
2057 //mShapeStrokeWidthUnitWidget->setEnabled( validSVG && strokeWidthParam );
2058 //mShapeStrokeUnitsDDBtn->setEnabled( validSVG && strokeWidthParam );
2059 mShapeSVGUnitsLabel->setEnabled( validSVG && strokeWidthParam );
2060}
2061
2062void QgsTextFormatWidget::updateAvailableShadowPositions()
2063{
2064 if ( mShadowUnderCmbBx->count() == 0
2065 || ( mShadowUnderCmbBx->findData( QgsTextShadowSettings::ShadowShape ) > -1 && mShapeTypeCmbBx->currentData().toInt() == QgsTextBackgroundSettings::ShapeMarkerSymbol )
2066 || ( mShadowUnderCmbBx->findData( QgsTextShadowSettings::ShadowShape ) == -1 && mShapeTypeCmbBx->currentData().toInt() != QgsTextBackgroundSettings::ShapeMarkerSymbol ) )
2067 {
2068 // showing invalid choices, have to rebuild the list
2069 const QgsTextShadowSettings::ShadowPlacement currentPlacement = static_cast<QgsTextShadowSettings::ShadowPlacement>( mShadowUnderCmbBx->currentData().toInt() );
2070 mShadowUnderCmbBx->clear();
2071
2072 mShadowUnderCmbBx->addItem( tr( "Lowest Label Component" ), QgsTextShadowSettings::ShadowLowest );
2073 mShadowUnderCmbBx->addItem( tr( "Text" ), QgsTextShadowSettings::ShadowText );
2074 mShadowUnderCmbBx->addItem( tr( "Buffer" ), QgsTextShadowSettings::ShadowBuffer );
2075 if ( mShapeTypeCmbBx->currentData().toInt() != QgsTextBackgroundSettings::ShapeMarkerSymbol )
2076 mShadowUnderCmbBx->addItem( tr( "Background" ), QgsTextShadowSettings::ShadowShape ); // not supported for marker symbol background shapes
2077
2078 mShadowUnderCmbBx->setCurrentIndex( mShadowUnderCmbBx->findData( currentPlacement ) );
2079 if ( mShadowUnderCmbBx->currentIndex() == -1 )
2080 mShadowUnderCmbBx->setCurrentIndex( 0 );
2081 }
2082}
2083
2084void QgsTextFormatWidget::updateProperty()
2085{
2086 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
2087 const QgsPalLayerSettings::Property key = static_cast<QgsPalLayerSettings::Property>( button->propertyKey() );
2088 mDataDefinedProperties.setProperty( key, button->toProperty() );
2089 updatePreview();
2090}
2091
2092void QgsTextFormatWidget::createAuxiliaryField()
2093{
2094 if ( !mLayer )
2095 return;
2096
2097 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
2098
2099 if ( !vLayer )
2100 return;
2101
2102 // try to create an auxiliary layer if not yet created
2103 if ( !vLayer->auxiliaryLayer() )
2104 {
2105 QgsNewAuxiliaryLayerDialog dlg( vLayer, this );
2106 dlg.exec();
2107 }
2108
2109 // return if still not exists
2110 if ( !vLayer->auxiliaryLayer() )
2111 return;
2112
2113 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
2114 const QgsPalLayerSettings::Property key = static_cast<QgsPalLayerSettings::Property>( button->propertyKey() );
2115 const QgsPropertyDefinition def = QgsPalLayerSettings::propertyDefinitions()[static_cast<int>( key )];
2116
2117 // create property in auxiliary storage if necessary
2118 if ( !vLayer->auxiliaryLayer()->exists( def ) )
2119 vLayer->auxiliaryLayer()->addAuxiliaryField( def );
2120
2121 // update property with join field name from auxiliary storage
2122 QgsProperty property = button->toProperty();
2123 property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
2124 property.setActive( true );
2125 button->updateFieldLists();
2126 button->setToProperty( property );
2127 mDataDefinedProperties.setProperty( key, button->toProperty() );
2128 updatePreview();
2129 emit auxiliaryFieldCreated();
2130}
2131
2132
2133void QgsTextFormatWidget::updateShapeFrameStatus()
2134{
2135 mShapeFrame->setEnabled( mShapeDrawDDBtn->isActive() || mShapeDrawChkBx->isChecked() );
2136}
2137
2138void QgsTextFormatWidget::updateBufferFrameStatus()
2139{
2140 mBufferFrame->setEnabled( mBufferDrawDDBtn->isActive() || mBufferDrawChkBx->isChecked() );
2141}
2142
2143void QgsTextFormatWidget::updateShadowFrameStatus()
2144{
2145 mShadowFrame->setEnabled( mShadowDrawDDBtn->isActive() || mShadowDrawChkBx->isChecked() );
2146}
2147
2148void QgsTextFormatWidget::updateCalloutFrameStatus()
2149{
2150 mCalloutFrame->setEnabled( mCalloutDrawDDBtn->isActive() || mCalloutsDrawCheckBox->isChecked() );
2151}
2152
2153void QgsTextFormatWidget::updateDataDefinedAlignment()
2154{
2155 // no data defined alignment without data defined position
2156 mCoordAlignmentFrame->setEnabled( ( mCoordXDDBtn->isActive() && mCoordYDDBtn->isActive() ) || mCoordPointDDBtn->isActive() );
2157}
2158
2159void QgsTextFormatWidget::overlapModeChanged()
2160{
2161 QString description;
2162 switch ( static_cast<Qgis::LabelOverlapHandling>( mComboOverlapHandling->currentData().toInt() ) )
2163 {
2165 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.)" );
2166 break;
2168 description = tr( "If a label cannot otherwise be placed for a feature then an overlapping label is permitted." );
2169 break;
2171 description = tr( "Labels from this layer may freely overlap other labels or label obstacles without penalty." );
2172 break;
2173 }
2174
2175 mOverlapModeDescriptionLabel->setText( u"<i>%1</i>"_s.arg( description ) );
2176}
2177
2178void QgsTextFormatWidget::updateCurvedLabelDescription()
2179{
2180 switch ( mComboCurvedLabelMode->currentData().value< Qgis::CurvedLabelMode >() )
2181 {
2183 mCurvedModeDescriptionLabel->hide();
2184 break;
2186 mCurvedModeDescriptionLabel->setText( tr( "Places individual characters from the label at each corresponding vertex in the line." ) );
2187 mCurvedModeDescriptionLabel->show();
2188 break;
2190 mCurvedModeDescriptionLabel->setText( tr( "Stretches (or shrinks) character spacing so that the curved label fits the whole line." ) );
2191 mCurvedModeDescriptionLabel->show();
2192 break;
2194 mCurvedModeDescriptionLabel->setText( tr( "Stretches (or shrinks) word spacing so that the curved label fits the whole line." ) );
2195 mCurvedModeDescriptionLabel->show();
2196 break;
2197 }
2198}
2199
2200void QgsTextFormatWidget::setFormatFromStyle( const QString &name, QgsStyle::StyleEntity type, const QString &stylePath )
2201{
2202 if ( name.isEmpty() )
2203 return;
2204
2205 QgsStyle *style = QgsProject::instance()->styleSettings()->styleAtPath( stylePath );
2206
2207 if ( !style )
2208 style = QgsStyle::defaultStyle();
2209
2210 switch ( type )
2211 {
2219 return;
2220
2222 {
2223 if ( !style->textFormatNames().contains( name ) )
2224 return;
2225
2226 const QgsTextFormat newFormat = style->textFormat( name );
2227 setFormat( newFormat );
2228 break;
2229 }
2230
2232 {
2233 if ( !style->labelSettingsNames().contains( name ) )
2234 return;
2235
2236 const QgsTextFormat newFormat = style->labelSettings( name ).format();
2237 setFormat( newFormat );
2238 break;
2239 }
2240 }
2241}
2242
2244{
2246 saveDlg.setDefaultTags( mTextFormatsListWidget->currentTagFilter() );
2247 if ( !saveDlg.exec() )
2248 return;
2249
2250 if ( saveDlg.name().isEmpty() )
2251 return;
2252
2253 QgsStyle *style = saveDlg.destinationStyle();
2254 if ( !style )
2255 return;
2256
2257 // check if there is no format with same name
2258 if ( style->textFormatNames().contains( saveDlg.name() ) )
2259 {
2260 const int res = QMessageBox::warning( this, tr( "Save Text Format" ), tr( "Format with name '%1' already exists. Overwrite?" ).arg( saveDlg.name() ), QMessageBox::Yes | QMessageBox::No );
2261 if ( res != QMessageBox::Yes )
2262 {
2263 return;
2264 }
2265 style->removeTextFormat( saveDlg.name() );
2266 }
2267
2268 const QStringList symbolTags = saveDlg.tags().split( ',' );
2269
2270 const QgsTextFormat newFormat = format();
2271 style->addTextFormat( saveDlg.name(), newFormat );
2272 style->saveTextFormat( saveDlg.name(), newFormat, saveDlg.isFavorite(), symbolTags );
2273}
2274
2275void QgsTextFormatWidget::mShapeSVGSelectorBtn_clicked()
2276{
2277 QgsSvgSelectorDialog svgDlg( this );
2278 svgDlg.setWindowTitle( tr( "Select SVG file" ) );
2279 svgDlg.svgSelector()->setSvgPath( mShapeSVGPathLineEdit->text().trimmed() );
2280
2281 if ( svgDlg.exec() == QDialog::Accepted )
2282 {
2283 const QString svgPath = svgDlg.svgSelector()->currentSvgPath();
2284 if ( !svgPath.isEmpty() )
2285 {
2286 mShapeSVGPathLineEdit->setText( svgPath );
2287 updatePreview();
2288 }
2289 }
2290}
2291
2292void QgsTextFormatWidget::mShapeSVGParamsBtn_clicked()
2293{
2294 const QString svgPath = mShapeSVGPathLineEdit->text();
2295 mLoadSvgParams = true;
2296 updateSvgWidgets( svgPath );
2297 mLoadSvgParams = false;
2298}
2299
2300void QgsTextFormatWidget::mShapeRotationCmbBx_currentIndexChanged( int index )
2301{
2302 mShapeRotationDblSpnBx->setEnabled( static_cast<QgsTextBackgroundSettings::RotationType>( index ) != QgsTextBackgroundSettings::RotationSync );
2303 mShapeRotationDDBtn->setEnabled( static_cast<QgsTextBackgroundSettings::RotationType>( index ) != QgsTextBackgroundSettings::RotationSync );
2304}
2305
2306void QgsTextFormatWidget::mPreviewTextEdit_textChanged( const QString &text )
2307{
2308 lblFontPreview->setText( text );
2309 updatePreview();
2310}
2311
2312void QgsTextFormatWidget::mPreviewTextBtn_clicked()
2313{
2314 mPreviewTextEdit->setText( u"Lorem Ipsum"_s );
2315 updatePreview();
2316}
2317
2318void QgsTextFormatWidget::mPreviewBackgroundBtn_colorChanged( const QColor &color )
2319{
2320 setPreviewBackground( color );
2321}
2322
2323void QgsTextFormatWidget::mDirectSymbLeftToolBtn_clicked()
2324{
2325 bool gotChar = false;
2326
2327 const QChar initial = !mDirectSymbLeftLineEdit->text().isEmpty() ? mDirectSymbLeftLineEdit->text().at( 0 ) : QChar();
2328 const QChar dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ), initial );
2329
2330 if ( !gotChar )
2331 return;
2332
2333 if ( !dirSymb.isNull() )
2334 mDirectSymbLeftLineEdit->setText( QString( dirSymb ) );
2335}
2336
2337void QgsTextFormatWidget::mDirectSymbRightToolBtn_clicked()
2338{
2339 bool gotChar = false;
2340 const QChar initial = !mDirectSymbRightLineEdit->text().isEmpty() ? mDirectSymbRightLineEdit->text().at( 0 ) : QChar();
2341 const QChar dirSymb = mCharDlg->selectCharacter( &gotChar, mRefFont, mFontDB.styleString( mRefFont ), initial );
2342
2343 if ( !gotChar )
2344 return;
2345
2346 if ( !dirSymb.isNull() )
2347 mDirectSymbRightLineEdit->setText( QString( dirSymb ) );
2348}
2349
2350void QgsTextFormatWidget::chkLineOrientationDependent_toggled( bool active )
2351{
2352 if ( active )
2353 {
2354 chkLineAbove->setText( tr( "Left of line" ) );
2355 chkLineBelow->setText( tr( "Right of line" ) );
2356 }
2357 else
2358 {
2359 chkLineAbove->setText( tr( "Above line" ) );
2360 chkLineBelow->setText( tr( "Below line" ) );
2361 }
2362}
2363
2364
2365void QgsTextFormatWidget::mToolButtonConfigureSubstitutes_clicked()
2366{
2367 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
2368 if ( panel && panel->dockMode() )
2369 {
2370 QgsSubstitutionListWidget *widget = new QgsSubstitutionListWidget( panel );
2371 widget->setPanelTitle( tr( "Substitutions" ) );
2373 connect( widget, &QgsSubstitutionListWidget::substitutionsChanged, this, &QgsTextFormatWidget::onSubstitutionsChanged );
2374 panel->openPanel( widget );
2375 return;
2376 }
2377
2378 QgsSubstitutionListDialog dlg( this );
2379 dlg.setSubstitutions( mSubstitutions );
2380 if ( dlg.exec() == QDialog::Accepted )
2381 {
2382 mSubstitutions = dlg.substitutions();
2383 emit widgetChanged();
2384 }
2385}
2386
2387void QgsTextFormatWidget::configureTabStops()
2388{
2389 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
2390 if ( panel && panel->dockMode() )
2391 {
2392 QgsTabPositionWidget *widget = new QgsTabPositionWidget( panel );
2393 widget->setPanelTitle( tr( "Tab Positions" ) );
2394 widget->setPositions( mTabPositions );
2395 widget->setUnit( mTabDistanceUnitWidget->unit() );
2396 connect( widget, &QgsTabPositionWidget::positionsChanged, this, [this]( const QList<QgsTextFormat::Tab> &positions ) {
2397 mTabPositions = positions;
2398 mTabStopDistanceSpin->setEnabled( mTabPositions.empty() );
2399 emit widgetChanged();
2400 } );
2401 panel->openPanel( widget );
2402 }
2403 else
2404 {
2405 QgsTabPositionDialog dlg( this );
2406 dlg.setPositions( mTabPositions );
2407 dlg.setUnit( mTabDistanceUnitWidget->unit() );
2408 if ( dlg.exec() == QDialog::Accepted )
2409 {
2410 mTabPositions = dlg.positions();
2411 mTabStopDistanceSpin->setEnabled( mTabPositions.empty() );
2412 emit widgetChanged();
2413 }
2414 }
2415}
2416
2417void QgsTextFormatWidget::showBackgroundRadius( bool show )
2418{
2419 mShapeRadiusLabel->setVisible( show );
2420 mShapeRadiusXDbSpnBx->setVisible( show );
2421
2422 mShapeRadiusYDbSpnBx->setVisible( show );
2423
2424 mShapeRadiusUnitWidget->setVisible( show );
2425
2426 mShapeRadiusDDBtn->setVisible( show );
2427 mShapeRadiusUnitsDDBtn->setVisible( show );
2428}
2429
2431{
2432 if ( auto *lExpressionContext = mContext.expressionContext() )
2433 return *lExpressionContext;
2434
2435 QgsExpressionContext expContext;
2436 if ( mMapCanvas )
2437 {
2438 expContext = mMapCanvas->createExpressionContext();
2439 }
2440 else
2441 {
2442 expContext
2447 }
2448
2449 if ( mLayer )
2451
2452 //TODO - show actual value
2453 expContext.setOriginalValueVariable( QVariant() );
2455
2456 return expContext;
2457}
2458
2460{
2461 if ( mGeometryGeneratorGroupBox->isChecked() )
2462 return mGeometryGeneratorType->currentData().value<Qgis::GeometryType>();
2463 else if ( QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer ) )
2464 return vLayer->geometryType();
2465 else
2466 return mGeomType;
2467}
2468
2469
2470//
2471// QgsTextFormatDialog
2472//
2473
2474QgsTextFormatDialog::QgsTextFormatDialog( const QgsTextFormat &format, QgsMapCanvas *mapCanvas, QWidget *parent, Qt::WindowFlags fl, QgsMapLayer *layer )
2475 : QDialog( parent, fl )
2476{
2477 setWindowTitle( tr( "Text Settings" ) );
2478
2479 mFormatWidget = new QgsTextFormatWidget( format, mapCanvas, this, layer );
2480 mFormatWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
2481
2482 QVBoxLayout *layout = new QVBoxLayout( this );
2483 layout->addWidget( mFormatWidget );
2484
2485 mButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, Qt::Horizontal, this );
2486 layout->addWidget( mButtonBox );
2487
2488 setLayout( layout );
2490
2491 connect( mButtonBox->button( QDialogButtonBox::Ok ), &QAbstractButton::clicked, this, &QDialog::accept );
2492 connect( mButtonBox->button( QDialogButtonBox::Cancel ), &QAbstractButton::clicked, this, &QDialog::reject );
2493 connect( mButtonBox->button( QDialogButtonBox::Help ), &QAbstractButton::clicked, this, &QgsTextFormatDialog::showHelp );
2494}
2495
2497{
2498 return mFormatWidget->format();
2499}
2500
2501void QgsTextFormatDialog::showHelp()
2502{
2503 QgsHelp::openHelp( u"style_library/label_settings.html#formatting-the-label-text"_s );
2504}
2505
2507{
2508 mFormatWidget->setContext( context );
2509}
2510
2511QDialogButtonBox *QgsTextFormatDialog::buttonBox() const
2512{
2513 return mButtonBox;
2514}
2515
2517 : QgsPanelWidgetWrapper( new QgsTextFormatWidget( format, mapCanvas, nullptr, layer ), parent )
2518{
2519 mFormatWidget = qobject_cast<QgsTextFormatWidget *>( widget() );
2520 connect( mFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [this] {
2521 if ( !mBlockSignals )
2522 emit changed();
2523 } );
2524}
2525
2527{
2528 return mFormatWidget->format();
2529}
2530
2532{
2533 mBlockSignals = true;
2534 mFormatWidget->setFormat( format );
2535 mBlockSignals = false;
2536}
2537
2539{
2540 mFormatWidget->setContext( context );
2541}
2542
2544{
2545 mFormatWidget->setDockMode( dockMode );
2547}
CurvedLabelMode
Modes which determine how curved labels are generated and placed.
Definition qgis.h:1326
@ StretchCharacterSpacingToFitLine
Increases (or decreases) the character spacing used for each label in order to fit the entire text ov...
Definition qgis.h:1329
@ Default
Default curved placement, characters are placed in an optimal position along the line....
Definition qgis.h:1327
@ StretchWordSpacingToFitLine
Increases (or decreases) the word spacing used for each label in order to fit the entire text over th...
Definition qgis.h:1330
@ PlaceCharactersAtVertices
Each individual character from the label text is placed such that their left-baseline position is loc...
Definition qgis.h:1328
@ LabelLargestPartOnly
Place a label only on the largest part from the geometry.
Definition qgis.h:1366
@ SplitLabelTextLinesOverParts
Splits the label text over the parts of the geometry, such that each consecutive part is labeled with...
Definition qgis.h:1368
@ LabelEveryPartWithEntireLabel
Place the (same) entire label over every part from the geometry.
Definition qgis.h:1367
@ FromPoint
Offset distance applies from point geometry.
Definition qgis.h:1382
@ FromSymbolBounds
Offset distance applies from rendered symbol bounds.
Definition qgis.h:1383
@ PreferCloser
Prefer closer labels, falling back to alternate positions before larger distances.
Definition qgis.h:1294
@ PreferPositionOrdering
Prefer labels follow position ordering, falling back to more distance labels before alternate positio...
Definition qgis.h:1295
LabelPlacement
Placement modes which determine how label candidates are generated for a feature.
Definition qgis.h:1307
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
Definition qgis.h:1309
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
Definition qgis.h:1311
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
Definition qgis.h:1308
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
Definition qgis.h:1310
@ Free
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
Definition qgis.h:1313
@ OrderedPositionsAroundPoint
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
Definition qgis.h:1314
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature or along a line feature....
Definition qgis.h:1312
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
Definition qgis.h:1315
@ OutsidePolygons
Candidates are placed outside of polygon boundaries. Applies to polygon layers only.
Definition qgis.h:1316
Capitalization
String capitalization options.
Definition qgis.h:3627
@ AllSmallCaps
Force all characters to small caps.
Definition qgis.h:3635
@ MixedCase
Mixed case, ie no change.
Definition qgis.h:3628
@ AllLowercase
Convert all characters to lowercase.
Definition qgis.h:3630
@ TitleCase
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
Definition qgis.h:3633
@ SmallCaps
Mixed case small caps.
Definition qgis.h:3632
@ ForceFirstLetterToCapital
Convert just the first letter of each word to uppercase, leave the rest untouched.
Definition qgis.h:3631
@ AllUppercase
Convert all characters to uppercase.
Definition qgis.h:3629
@ AboveRight
Above right.
Definition qgis.h:1398
@ BelowLeft
Below left.
Definition qgis.h:1402
@ Above
Above center.
Definition qgis.h:1397
@ BelowRight
Below right.
Definition qgis.h:1404
@ Right
Right middle.
Definition qgis.h:1401
@ AboveLeft
Above left.
Definition qgis.h:1396
@ Below
Below center.
Definition qgis.h:1403
@ Over
Center middle.
Definition qgis.h:1400
TextOrientation
Text orientations.
Definition qgis.h:3111
@ Vertical
Vertically oriented text.
Definition qgis.h:3113
@ RotationBased
Horizontally or vertically oriented text based on rotation (only available for map labeling).
Definition qgis.h:3114
@ Horizontal
Horizontally oriented text.
Definition qgis.h:3112
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:399
@ Point
Points.
Definition qgis.h:400
@ Line
Lines.
Definition qgis.h:401
@ Polygon
Polygons.
Definition qgis.h:402
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size).
Definition qgis.h:5762
@ Millimeters
Millimeters.
Definition qgis.h:5759
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5763
@ MapUnits
Map units.
Definition qgis.h:5760
@ Pixels
Pixels.
Definition qgis.h:5761
@ Inches
Inches.
Definition qgis.h:5764
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5766
@ Marker
Marker symbol.
Definition qgis.h:672
@ Fill
Fill symbol.
Definition qgis.h:674
@ Point
Point.
Definition qgis.h:316
@ LineString
LineString.
Definition qgis.h:317
@ Polygon
Polygon.
Definition qgis.h:318
LabelOverlapHandling
Label overlap handling.
Definition qgis.h:1268
@ AllowOverlapAtNoCost
Labels may freely overlap other labels, at no cost.
Definition qgis.h:1271
@ AllowOverlapIfRequired
Avoids overlapping labels when possible, but permit overlaps if labels for features cannot otherwise ...
Definition qgis.h:1270
@ PreventOverlap
Do not allow labels to overlap other labels.
Definition qgis.h:1269
@ FlipUpsideDownLabels
Upside-down labels (90 <= angle < 270) are shown upright.
Definition qgis.h:1464
@ AlwaysAllowUpsideDown
Show upside down for all labels, including dynamic ones.
Definition qgis.h:1466
@ AllowUpsideDownWhenRotationIsDefined
Show upside down when rotation is layer- or data-defined.
Definition qgis.h:1465
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...
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
bool addAuxiliaryField(const QgsPropertyDefinition &definition)
Adds an auxiliary field for the given property.
bool exists(const QgsPropertyDefinition &definition) const
Returns true if the property is stored in the layer already, false otherwise.
void collapsedStateChanged(bool collapsed)
Signal emitted when groupbox collapsed/expanded state is changed, and when first shown.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
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 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.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
static QFont createFont(const QString &family, int pointSize=-1, int weight=-1, bool italic=false)
Creates a font with the specified family.
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 setFontFamily(QFont &font, const QString &family)
Sets the family for a font object.
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:225
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:41
static QIcon iconForWkbType(Qgis::WkbType 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.
Map canvas is a class for displaying all GIS data types on a canvas.
Base class for all map layer types.
Definition qgsmaplayer.h:83
Contains configuration for rendering maps.
A marker symbol type, for rendering Point and MultiPoint geometries.
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
static std::unique_ptr< QgsPaintEffect > defaultStack()
Returns a new effect stack consisting of a sensible selection of default effects.
Property
Data definable properties.
@ PositionX
X-coordinate data defined label position.
@ LinePlacementOptions
Line placement flags.
@ WhitespaceCollisionHandling
Whitespace collision handling.
@ AllowDegradedPlacement
Allow degraded label placements.
@ MaskEnabled
Whether the mask is enabled.
@ OverlapHandling
Overlap handling technique.
@ PositionY
Y-coordinate data defined label position.
@ MaximumScale
Maximum map scale (ie most "zoomed in").
@ Vali
Vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top).
@ MinimumScale
Minimum map scale (ie most "zoomed out").
@ FontStretchFactor
Font stretch factor, since QGIS 3.24.
@ PolygonLabelOutside
Whether labels outside a polygon feature are permitted, or should be forced.
@ LabelAllParts
Multipart geometry behavior.
@ LabelMarginDistance
Minimum distance from labels for this feature to other labels.
@ Hali
Horizontal alignment for data defined label position (Left, Center, Right).
@ OverrunDistance
Distance which labels can extend past either end of linear features.
@ MaskBufferUnit
Mask buffer size unit.
@ CurvedLabelMode
Mode which determine how curved labels are generated and placed.
@ MaskBufferSize
Mask buffer size.
@ TabStopDistance
Tab stop distance, since QGIS 3.38.
@ RemoveDuplicateLabels
Whether this feature can cause removal of duplicate labels.
@ PositionPoint
Point-coordinate data defined label position.
@ MaximumDistance
Maximum distance of label from feature.
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.
QWidget * widget()
Returns the internal widget that is wrapped in this panel.
QgsPanelWidgetWrapper(QWidget *widget, QWidget *parent=nullptr)
Wrapper widget for existing widgets which can't have the inheritance tree changed,...
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
bool dockMode() const
Returns the dock mode state.
void changed()
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.
QgsStyle * styleAtPath(const QString &path)
Returns a reference to the style database associated with the project with matching file path.
QVector< double > mapScales() const
Returns the list of custom project map scales.
static QgsProject * instance()
Returns the QgsProject singleton instance.
const QgsProjectStyleSettings * styleSettings() const
Returns the project's style settings, which contains settings and properties relating to how a QgsPro...
const QgsProjectViewSettings * viewSettings() const
Returns the project's view settings, which contains settings and properties relating to how a QgsProj...
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
QSet< int > propertyKeys() const final
Returns a list of property keys contained within the collection.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
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.
void setField(const QString &field)
Sets the field name the property references.
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
Stores settings for use within QGIS.
Definition qgssettings.h:68
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.
A database of saved style entities, including symbols, color ramps, text formats and others.
Definition qgsstyle.h:91
QgsTextFormat textFormat(const QString &name) const
Returns the text format with the specified name.
QStringList textFormatNames() const
Returns a list of names of text formats in the style.
bool removeTextFormat(const QString &name)
Removes a text format from the style.
StyleEntity
Enum for Entities involved in a style.
Definition qgsstyle.h:206
@ LabelSettingsEntity
Label settings.
Definition qgsstyle.h:212
@ TextFormatEntity
Text formats.
Definition qgsstyle.h:211
@ SmartgroupEntity
Smart groups.
Definition qgsstyle.h:210
@ Symbol3DEntity
3D symbol entity
Definition qgsstyle.h:214
@ SymbolEntity
Symbols.
Definition qgsstyle.h:207
@ TagEntity
Tags.
Definition qgsstyle.h:208
@ ColorrampEntity
Color ramps.
Definition qgsstyle.h:209
@ LegendPatchShapeEntity
Legend patch shape.
Definition qgsstyle.h:213
@ MaterialSettingsEntity
Material settings.
Definition qgsstyle.h:215
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:164
QStringList labelSettingsNames() const
Returns a list of names of label settings in the style.
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,...
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:390
QgsPalLayerSettings labelSettings(const QString &name) const
Returns the label settings with the specified name.
bool saveTextFormat(const QString &name, const QgsTextFormat &format, bool favorite, const QStringList &tags)
Adds a text format to the database.
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 dialog for selection of an SVG file.
A button for creating and modifying QgsSymbol settings.
void changed()
Emitted when the symbol's settings are changed.
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,...
static std::unique_ptr< QgsSymbol > defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
void setUnit(Qgis::RenderUnit unit)
Sets the unit type used for the tab positions (used to update interface labels).
void setPositions(const QList< QgsTextFormat::Tab > &positions)
Sets the tab positions to show in the widget.
void positionsChanged(const QList< QgsTextFormat::Tab > &positions)
Emitted when positions are changed in the widget.
Container for settings relating to a text background object.
QgsMapUnitScale strokeWidthMapUnitScale() const
Returns the map unit scale object for the shape stroke width.
void setRadiiUnit(Qgis::RenderUnit units)
Sets the units used for the shape's radii.
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.
Qgis::RenderUnit radiiUnit() const
Returns the units used for the shape's radii.
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.
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.
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...
Qgis::RenderUnit strokeWidthUnit() const
Returns the units used for the shape's stroke width.
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...
@ 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 setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the shape's size.
Qgis::RenderUnit offsetUnit() const
Returns the units used for the shape's offset.
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).
Qgis::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.
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 setStrokeWidthUnit(Qgis::RenderUnit units)
Sets the units used for the shape's stroke width.
void setOffsetUnit(Qgis::RenderUnit units)
Sets the units used for the shape's offset.
void setOffset(QPointF offset)
Sets the offset used for drawing the background shape.
void setSize(QSizeF size)
Sets the size of the background shape.
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.
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.
Qgis::RenderUnit sizeUnit() const
Returns the units for the buffer size.
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.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
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.
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 setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the buffer.
void setSize(double size)
Sets the size of the buffer.
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...
QgsTextFormatDialog(const QgsTextFormat &format, QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags, QgsMapLayer *layer=nullptr)
Constructor for QgsTextFormatDialog.
void setFormat(const QgsTextFormat &format)
Sets the format to show in the widget.
QgsTextFormatPanelWidget(const QgsTextFormat &format, QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr, QgsMapLayer *layer=nullptr)
Constructor for QgsTextFormatPanelWidget.
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...
A widget for customizing text formatting settings.
void updatePlacementWidgets()
Updates label placement options to reflect current state of widget.
QListWidgetItem * mMaskItem
Mask widget item.
QButtonGroup * mUpsidedownBtnGrp
Upside down labels button group.
int mMinPixelLimit
Pixel size font limit.
QListWidgetItem * mBackgroundItem
Background widget item.
void setDockMode(bool enabled)
Sets whether the widget should be shown in a compact dock mode.
QgsMapCanvas * mMapCanvas
Associated map canvas.
void setPropertyOverrideButtonsVisible(bool visible)
Toggles whether data defined buttons should be shown in the widget.
QgsSymbolWidgetContext context() const
Returns the context in which the widget is shown, e.g., the associated map canvas and expression cont...
QgsTextFormatWidget(const QgsTextFormat &format=QgsTextFormat(), QgsMapCanvas *mapCanvas=nullptr, QWidget *parent=nullptr, QgsMapLayer *layer=nullptr)
Constructor for QgsTextFormatWidget.
QListWidgetItem * mFormattingItem
Formatting widget item.
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.
QListWidgetItem * mTextItem
Text widget item.
Qgis::GeometryType mGeomType
Geometry type for layer, if known.
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.
QListWidgetItem * mShadowItem
Shadow widget item.
QList< QgsTextFormat::Tab > mTabPositions
Tab positions.
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.
QListWidgetItem * mBufferItem
Buffer widget item.
void updateLinePlacementOptions()
Updates line placement options to reflect current state of widget.
QListWidgetItem * mCalloutItem
Callout widget item.
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...
QListWidgetItem * mRenderingItem
Rendering widget item.
void updatePreview()
Updates the text preview.
QListWidgetItem * mPlacementItem
Placement widget item.
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.
Qgis::GeometryType labelGeometryType() const
Returns the geometry type which will be used by the labeling engine when registering labels for the l...
QgsMapLayer * mLayer
Associated vector layer.
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.
Container for all settings relating to text rendering.
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.
Qgis::RenderUnit sizeUnit() const
Returns the units for the buffer size.
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.
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.
double opacity() const
Returns the mask's opacity.
bool enabled() const
Returns whether the mask is enabled.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
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.
void setBlurRadiusUnit(Qgis::RenderUnit units)
Sets the units used for the shadow's blur radius.
bool enabled() const
Returns whether the shadow is enabled.
void setOffsetUnit(Qgis::RenderUnit units)
Sets the units used for the shadow's offset.
int scale() const
Returns the scaling used for the drop shadow (in percentage of original size).
Qgis::RenderUnit offsetUnit() const
Returns the units used for the shadow's offset.
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.
Qgis::RenderUnit blurRadiusUnit() const
Returns the units used for the shadow's blur radius.
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.
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.
double blurRadius() const
Returns the blur radius for the shadow.
void setBlurRadius(double blurRadius)
Sets the blur radius for the shadow.
void setEnabled(bool enabled)
Sets whether the text shadow will be drawn.
void changed()
Emitted when the selected unit is changed, or the definition of the map unit scale is changed.
QList< Qgis::RenderUnit > RenderUnitList
List of render units.
Represents a vector layer which manages a vector based dataset.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
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:7637