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