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