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