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