QGIS API Documentation 3.99.0-Master (09f76ad7019)
Loading...
Searching...
No Matches
qgslabelinggui.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslabelinggui.cpp
3 Smart labeling for vector layers
4 -------------------
5 begin : June 2009
6 copyright : (C) Martin Dobias
7 email : wonder dot sk at gmail dot com
8
9 ***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgslabelinggui.h"
19
21#include "qgsapplication.h"
22#include "qgscallout.h"
23#include "qgscalloutsregistry.h"
26#include "qgsgui.h"
27#include "qgshelp.h"
31#include "qgsmapcanvas.h"
32#include "qgsmeshlayer.h"
33#include "qgsproject.h"
35#include "qgsstylesavedialog.h"
36#include "qgsvectorlayer.h"
37#include "qgsvectortilelayer.h"
38
39#include <QButtonGroup>
40#include <QMessageBox>
41#include <QString>
42
43#include "moc_qgslabelinggui.cpp"
44
45using namespace Qt::StringLiterals;
46
48
49QgsExpressionContext QgsLabelingGui::createExpressionContext() const
50{
51 QgsExpressionContext expContext;
52 if ( mMapCanvas )
53 {
54 expContext = mMapCanvas->createExpressionContext();
55 }
56 else
57 {
61 }
62
63 if ( mLayer )
64 expContext << QgsExpressionContextUtils::layerScope( mLayer );
65
66 if ( mLayer && mLayer->type() == Qgis::LayerType::Mesh )
67 {
68 if ( mGeomType == Qgis::GeometryType::Point )
70 else if ( mGeomType == Qgis::GeometryType::Polygon )
72 }
73
74 expContext << QgsExpressionContextUtils::updateSymbolScope( nullptr, new QgsExpressionContextScope() );
75
76 //TODO - show actual value
77 expContext.setOriginalValueVariable( QVariant() );
79
80 return expContext;
81}
82
83void QgsLabelingGui::updateCalloutWidget( QgsCallout *callout )
84{
85 if ( !callout )
86 {
87 mCalloutStackedWidget->setCurrentWidget( pageDummy );
88 return;
89 }
90
91 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
92 if ( !vLayer )
93 {
94 mCalloutStackedWidget->setCurrentWidget( pageDummy );
95 return;
96 }
97
98 if ( mCalloutStackedWidget->currentWidget() != pageDummy )
99 {
100 // stop updating from the original widget
101 if ( QgsCalloutWidget *pew = qobject_cast<QgsCalloutWidget *>( mCalloutStackedWidget->currentWidget() ) )
102 disconnect( pew, &QgsCalloutWidget::changed, this, &QgsLabelingGui::updatePreview );
103 }
104
105 QgsCalloutRegistry *registry = QgsApplication::calloutRegistry();
106 if ( QgsCalloutAbstractMetadata *am = registry->calloutMetadata( callout->type() ) )
107 {
108 if ( QgsCalloutWidget *w = am->createCalloutWidget( vLayer ) )
109 {
110 Qgis::GeometryType geometryType = mGeomType;
111 if ( mGeometryGeneratorGroupBox->isChecked() )
112 geometryType = mGeometryGeneratorType->currentData().value<Qgis::GeometryType>();
113 else if ( vLayer )
114 geometryType = vLayer->geometryType();
115 w->setGeometryType( geometryType );
116 w->setCallout( callout );
117
118 w->setContext( context() );
119 mCalloutStackedWidget->addWidget( w );
120 mCalloutStackedWidget->setCurrentWidget( w );
121 // start receiving updates from widget
122 connect( w, &QgsCalloutWidget::changed, this, &QgsLabelingGui::updatePreview );
123 return;
124 }
125 }
126 // When anything is not right
127 mCalloutStackedWidget->setCurrentWidget( pageDummy );
128}
129
130void QgsLabelingGui::showObstacleSettings()
131{
132 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
133 if ( !vLayer )
134 {
135 return;
136 }
137
138 QgsExpressionContext context = createExpressionContext();
139
140 QgsSymbolWidgetContext symbolContext;
141 symbolContext.setExpressionContext( &context );
142 symbolContext.setMapCanvas( mMapCanvas );
143
144 QgsLabelObstacleSettingsWidget *widget = new QgsLabelObstacleSettingsWidget( nullptr, vLayer );
145 widget->setDataDefinedProperties( mDataDefinedProperties );
146 widget->setSettings( mObstacleSettings );
147 widget->setGeometryType( vLayer->geometryType() );
148 widget->setContext( symbolContext );
149
150 auto applySettings = [this, widget] {
151 mObstacleSettings = widget->settings();
152 const QgsPropertyCollection obstacleDataDefinedProperties = widget->dataDefinedProperties();
153 widget->updateDataDefinedProperties( mDataDefinedProperties );
154 emit widgetChanged();
155 };
156
157 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
158 if ( panel && panel->dockMode() )
159 {
160 connect( widget, &QgsLabelSettingsWidgetBase::changed, this, [applySettings] {
161 applySettings();
162 } );
163 panel->openPanel( widget );
164 }
165 else
166 {
167 QgsLabelSettingsWidgetDialog dialog( widget, this );
168
169 dialog.buttonBox()->addButton( QDialogButtonBox::Help );
170 connect( dialog.buttonBox(), &QDialogButtonBox::helpRequested, this, [] {
171 QgsHelp::openHelp( u"style_library/label_settings.html#obstacles"_s );
172 } );
173
174 if ( dialog.exec() )
175 {
176 applySettings();
177 }
178 // reactivate button's window
179 activateWindow();
180 }
181}
182
183void QgsLabelingGui::showLineAnchorSettings()
184{
185 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
186 if ( !vLayer )
187 {
188 return;
189 }
190
191 QgsExpressionContext context = createExpressionContext();
192
193 QgsSymbolWidgetContext symbolContext;
194 symbolContext.setExpressionContext( &context );
195 symbolContext.setMapCanvas( mMapCanvas );
196
197 QgsLabelLineAnchorWidget *widget = new QgsLabelLineAnchorWidget( nullptr, vLayer );
198 widget->setDataDefinedProperties( mDataDefinedProperties );
199 widget->setSettings( mLineSettings );
200 widget->setGeometryType( vLayer->geometryType() );
201 widget->setContext( symbolContext );
202
203 auto applySettings = [this, widget] {
204 const QgsLabelLineSettings widgetSettings = widget->settings();
205 mLineSettings.setLineAnchorPercent( widgetSettings.lineAnchorPercent() );
206 mLineSettings.setAnchorType( widgetSettings.anchorType() );
207 mLineSettings.setAnchorClipping( widgetSettings.anchorClipping() );
208 mLineSettings.setAnchorTextPoint( widgetSettings.anchorTextPoint() );
209 const QgsPropertyCollection obstacleDataDefinedProperties = widget->dataDefinedProperties();
210 widget->updateDataDefinedProperties( mDataDefinedProperties );
211 emit widgetChanged();
212 };
213
214 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
215 if ( panel && panel->dockMode() )
216 {
217 connect( widget, &QgsLabelSettingsWidgetBase::changed, this, [applySettings] {
218 applySettings();
219 } );
220 panel->openPanel( widget );
221 }
222 else
223 {
224 QgsLabelSettingsWidgetDialog dialog( widget, this );
225
226 dialog.buttonBox()->addButton( QDialogButtonBox::Help );
227 connect( dialog.buttonBox(), &QDialogButtonBox::helpRequested, this, [] {
228 QgsHelp::openHelp( u"style_library/label_settings.html#placement-for-line-layers"_s );
229 } );
230
231 if ( dialog.exec() )
232 {
233 applySettings();
234 }
235 // reactivate button's window
236 activateWindow();
237 }
238}
239
240void QgsLabelingGui::showDuplicateSettings()
241{
242 QgsExpressionContext context = createExpressionContext();
243
244 QgsSymbolWidgetContext symbolContext;
245 symbolContext.setExpressionContext( &context );
246 symbolContext.setMapCanvas( mMapCanvas );
247
248 QgsLabelRemoveDuplicatesSettingsWidget *widget = new QgsLabelRemoveDuplicatesSettingsWidget( nullptr, mLayer );
249 widget->setDataDefinedProperties( mDataDefinedProperties );
250 widget->setSettings( mThinningSettings );
251 auto vectorLayer = qobject_cast< QgsVectorLayer * >( mLayer );
252 widget->setGeometryType( vectorLayer ? vectorLayer->geometryType() : Qgis::GeometryType::Unknown );
253 widget->setContext( symbolContext );
254
255 auto applySettings = [this, widget] {
256 mThinningSettings = widget->settings();
257 const QgsPropertyCollection obstacleDataDefinedProperties = widget->dataDefinedProperties();
258 widget->updateDataDefinedProperties( mDataDefinedProperties );
259 emit widgetChanged();
260 };
261
262 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
263 if ( panel && panel->dockMode() )
264 {
265 connect( widget, &QgsLabelSettingsWidgetBase::changed, this, [applySettings] {
266 applySettings();
267 } );
268 panel->openPanel( widget );
269 }
270 else
271 {
272 QgsLabelSettingsWidgetDialog dialog( widget, this );
273 if ( dialog.exec() )
274 {
275 applySettings();
276 }
277 // reactivate button's window
278 activateWindow();
279 }
280}
281
282QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsPalLayerSettings &layerSettings, QWidget *parent, Qgis::GeometryType geomType )
283 : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, layer )
284 , mMode( NoLabels )
285 , mSettings( layerSettings )
286{
287 mGeomType = geomType;
288
289 init();
290
291 setLayer( layer );
292}
293
294QgsLabelingGui::QgsLabelingGui( QgsMeshLayer *layer, QgsMapCanvas *mapCanvas, const QgsPalLayerSettings &settings, QWidget *parent, Qgis::GeometryType geomType )
295 : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, layer )
296 , mMode( NoLabels )
297 , mSettings( settings )
298{
299 mGeomType = geomType;
300
301 init();
302
303 setLayer( layer );
304}
305
306QgsLabelingGui::QgsLabelingGui( QgsVectorTileLayer *layer, QgsMapCanvas *mapCanvas, const QgsPalLayerSettings &settings, QWidget *parent, Qgis::GeometryType geomType )
307 : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, layer )
308 , mMode( NoLabels )
309 , mSettings( settings )
310{
311 mGeomType = geomType;
312
313 init();
314
315 setLayer( layer );
316}
317
318
319QgsLabelingGui::QgsLabelingGui( QgsMapCanvas *mapCanvas, QWidget *parent, QgsMapLayer *layer )
320 : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, layer )
321 , mMode( NoLabels )
322{
323}
324
325
326QgsLabelingGui::QgsLabelingGui( QgsMapCanvas *mapCanvas, const QgsPalLayerSettings &settings, QWidget *parent )
327 : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, nullptr )
328 , mMode( NoLabels )
329 , mSettings( settings )
330{
331 init();
332
333 setLayer( nullptr );
334}
335
336void QgsLabelingGui::init()
337{
339
340 mStackedWidgetLabelWith->setSizeMode( QgsStackedWidget::SizeMode::CurrentPageOnly );
341
342 mFontMultiLineAlignComboBox->addItem( tr( "Left" ), static_cast<int>( Qgis::LabelMultiLineAlignment::Left ) );
343 mFontMultiLineAlignComboBox->addItem( tr( "Center" ), static_cast<int>( Qgis::LabelMultiLineAlignment::Center ) );
344 mFontMultiLineAlignComboBox->addItem( tr( "Right" ), static_cast<int>( Qgis::LabelMultiLineAlignment::Right ) );
345 mFontMultiLineAlignComboBox->addItem( tr( "Justify" ), static_cast<int>( Qgis::LabelMultiLineAlignment::Justify ) );
346
347 mCoordRotationUnitComboBox->addItem( QgsUnitTypes::toString( Qgis::AngleUnit::Degrees ), static_cast<int>( Qgis::AngleUnit::Degrees ) );
348 mCoordRotationUnitComboBox->addItem( QgsUnitTypes::toString( Qgis::AngleUnit::Radians ), static_cast<int>( Qgis::AngleUnit::Radians ) );
349 mCoordRotationUnitComboBox->addItem( QgsUnitTypes::toString( Qgis::AngleUnit::Gon ), static_cast<int>( Qgis::AngleUnit::Gon ) );
350 mCoordRotationUnitComboBox->addItem( QgsUnitTypes::toString( Qgis::AngleUnit::MinutesOfArc ), static_cast<int>( Qgis::AngleUnit::MinutesOfArc ) );
351 mCoordRotationUnitComboBox->addItem( QgsUnitTypes::toString( Qgis::AngleUnit::SecondsOfArc ), static_cast<int>( Qgis::AngleUnit::SecondsOfArc ) );
352 mCoordRotationUnitComboBox->addItem( QgsUnitTypes::toString( Qgis::AngleUnit::Turn ), static_cast<int>( Qgis::AngleUnit::Turn ) );
353 mCoordRotationUnitComboBox->addItem( QgsUnitTypes::toString( Qgis::AngleUnit::MilliradiansSI ), static_cast<int>( Qgis::AngleUnit::MilliradiansSI ) );
354 mCoordRotationUnitComboBox->addItem( QgsUnitTypes::toString( Qgis::AngleUnit::MilNATO ), static_cast<int>( Qgis::AngleUnit::MilNATO ) );
355
356 // connections for groupboxes with separate activation checkboxes (that need to honor data defined setting)
357 connect( mBufferDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
358 connect( mBufferDrawDDBtn, &QgsPropertyOverrideButton::changed, this, &QgsLabelingGui::updateUi );
359 connect( mEnableMaskChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
360 connect( mShapeDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
361 connect( mCalloutsDrawCheckBox, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
362 connect( mShadowDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
363 connect( mDirectSymbChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
364 connect( mFormatNumChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
365 connect( mScaleBasedVisibilityChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
366 connect( mFontLimitPixelChkBox, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
367 connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
368 connect( mGeometryGeneratorType, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
369 connect( mGeometryGeneratorExpressionButton, &QToolButton::clicked, this, &QgsLabelingGui::showGeometryGeneratorExpressionBuilder );
370 connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
371 connect( mGeometryGenerator, &QgsCodeEditorExpression::textChanged, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
372 connect( mGeometryGeneratorType, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::validateGeometryGeneratorExpression );
373 connect( mObstacleSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingGui::showObstacleSettings );
374 connect( mLineAnchorSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingGui::showLineAnchorSettings );
375 connect( mDuplicateSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingGui::showDuplicateSettings );
376
377 mFieldExpressionWidget->registerExpressionContextGenerator( this );
378
379 mMinScaleWidget->setMapCanvas( mMapCanvas );
380 mMinScaleWidget->setShowCurrentScaleButton( true );
381 mMaxScaleWidget->setMapCanvas( mMapCanvas );
382 mMaxScaleWidget->setShowCurrentScaleButton( true );
383
384 mGeometryGeneratorExpressionButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
385 mGeometryGeneratorExpressionButton->setIcon( QgsApplication::getThemeIcon( u"/mIconExpression.svg"_s ) );
386
387 const QStringList calloutTypes = QgsApplication::calloutRegistry()->calloutTypes();
388 for ( const QString &type : calloutTypes )
389 {
390 mCalloutStyleComboBox->addItem( QgsApplication::calloutRegistry()->calloutMetadata( type )->icon(), QgsApplication::calloutRegistry()->calloutMetadata( type )->visibleName(), type );
391 }
392
393 mGeometryGeneratorWarningLabel->setStyleSheet( u"color: #FFC107;"_s );
394 mGeometryGeneratorWarningLabel->setTextInteractionFlags( Qt::TextBrowserInteraction );
395 connect( mGeometryGeneratorWarningLabel, &QLabel::linkActivated, this, [this]( const QString &link ) {
396 if ( link == "#determineGeometryGeneratorType"_L1 )
397 determineGeometryGeneratorType();
398 } );
399
400 connect( mCalloutStyleComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::calloutTypeChanged );
401
402 mLblNoObstacle1->installEventFilter( this );
403}
404
405void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
406{
407 mPreviewFeature = QgsFeature();
408
409 if ( ( !mapLayer || mapLayer->type() != Qgis::LayerType::Vector ) && mGeomType == Qgis::GeometryType::Unknown )
410 {
411 setEnabled( false );
412 return;
413 }
414
415 setEnabled( true );
416
417 mLayer = mapLayer;
418 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mapLayer );
419
420 mTextFormatsListWidget->setLayerType( vLayer ? vLayer->geometryType() : mGeomType );
421 mBackgroundMarkerSymbolButton->setLayer( vLayer );
422 mBackgroundFillSymbolButton->setLayer( vLayer );
423
424 // load labeling settings from layer
425 updateGeometryTypeBasedWidgets();
426
427 mFieldExpressionWidget->setLayer( mapLayer );
428 QgsDistanceArea da;
429 if ( mLayer )
430 da.setSourceCrs( mLayer->crs(), QgsProject::instance()->transformContext() );
431 da.setEllipsoid( QgsProject::instance()->ellipsoid() );
432 mFieldExpressionWidget->setGeomCalculator( da );
433
434 mFieldExpressionWidget->setEnabled( mMode == Labels || !mLayer );
435 mLabelingFrame->setEnabled( mMode == Labels || !mLayer );
436
437 blockInitSignals( true );
438
439 mGeometryGenerator->setText( mSettings.geometryGenerator );
440 mGeometryGeneratorGroupBox->setChecked( mSettings.geometryGeneratorEnabled );
441 if ( !mSettings.geometryGeneratorEnabled )
442 mGeometryGeneratorGroupBox->setCollapsed( true );
443 mGeometryGeneratorType->setCurrentIndex( mGeometryGeneratorType->findData( QVariant::fromValue( mSettings.geometryGeneratorType ) ) );
444
445 updateWidgetForFormat( mSettings.format().isValid() ? mSettings.format() : QgsStyle::defaultTextFormatForProject( QgsProject::instance(), QgsStyle::TextFormatContext::Labeling ) );
446
447 mFieldExpressionWidget->setRow( -1 );
448 mFieldExpressionWidget->setField( mSettings.fieldName );
449 mCheckBoxSubstituteText->setChecked( mSettings.useSubstitutions );
450 mSubstitutions = mSettings.substitutions;
451
452 // populate placement options
453 mCentroidRadioWhole->setChecked( mSettings.centroidWhole );
454 mCentroidInsideCheckBox->setChecked( mSettings.centroidInside );
455 mFitInsidePolygonCheckBox->setChecked( mSettings.fitInPolygonOnly );
456 mLineDistanceSpnBx->setValue( mSettings.dist );
457 mLineDistanceUnitWidget->setUnit( mSettings.distUnits );
458 mLineDistanceUnitWidget->setMapUnitScale( mSettings.distMapUnitScale );
459
460 mMaximumDistanceSpnBx->setValue( mSettings.pointSettings().maximumDistance() );
461 mMaximumDistanceUnitWidget->setUnit( mSettings.pointSettings().maximumDistanceUnit() );
462 mMaximumDistanceUnitWidget->setMapUnitScale( mSettings.pointSettings().maximumDistanceMapUnitScale() );
463
464 mOffsetTypeComboBox->setCurrentIndex( mOffsetTypeComboBox->findData( static_cast<int>( mSettings.offsetType ) ) );
465 mQuadrantBtnGrp->button( static_cast<int>( mSettings.pointSettings().quadrant() ) )->setChecked( true );
466 mPointOffsetXSpinBox->setValue( mSettings.xOffset );
467 mPointOffsetYSpinBox->setValue( mSettings.yOffset );
468 mPointOffsetUnitWidget->setUnit( mSettings.offsetUnits );
469 mPointOffsetUnitWidget->setMapUnitScale( mSettings.labelOffsetMapUnitScale );
470 mPointAngleSpinBox->setValue( mSettings.angleOffset );
471 chkLineAbove->setChecked( mSettings.lineSettings().placementFlags() & Qgis::LabelLinePlacementFlag::AboveLine );
472 chkLineBelow->setChecked( mSettings.lineSettings().placementFlags() & Qgis::LabelLinePlacementFlag::BelowLine );
473 chkLineOn->setChecked( mSettings.lineSettings().placementFlags() & Qgis::LabelLinePlacementFlag::OnLine );
474 chkLineOrientationDependent->setChecked( !( mSettings.lineSettings().placementFlags() & Qgis::LabelLinePlacementFlag::MapOrientation ) );
475
476 mCheckAllowLabelsOutsidePolygons->setChecked( mSettings.polygonPlacementFlags() & Qgis::LabelPolygonPlacementFlag::AllowPlacementOutsideOfPolygon );
477
478 const int placementIndex = mPlacementModeComboBox->findData( static_cast<int>( mSettings.placement ) );
479 if ( placementIndex >= 0 )
480 {
481 mPlacementModeComboBox->setCurrentIndex( placementIndex );
482 }
483 else
484 {
485 // use default placement for layer type
486 mPlacementModeComboBox->setCurrentIndex( 0 );
487 }
488
489 // Label repeat distance
490 mRepeatDistanceSpinBox->setValue( mSettings.repeatDistance );
491 mRepeatDistanceUnitWidget->setUnit( mSettings.repeatDistanceUnit );
492 mRepeatDistanceUnitWidget->setMapUnitScale( mSettings.repeatDistanceMapUnitScale );
493
494 mOverrunDistanceSpinBox->setValue( mSettings.lineSettings().overrunDistance() );
495 mOverrunDistanceUnitWidget->setUnit( mSettings.lineSettings().overrunDistanceUnit() );
496 mOverrunDistanceUnitWidget->setMapUnitScale( mSettings.lineSettings().overrunDistanceMapUnitScale() );
497
498 mThinningSettings = mSettings.thinningSettings();
499
500 mLabelMarginSpinBox->setValue( mThinningSettings.labelMarginDistance() );
501 mLabelMarginUnitWidget->setUnit( mThinningSettings.labelMarginDistanceUnit() );
502 mLabelMarginUnitWidget->setMapUnitScale( mThinningSettings.labelMarginDistanceMapUnitScale() );
503
504 mPrioritySlider->setValue( mSettings.priority );
505 mChkNoObstacle->setChecked( mSettings.obstacleSettings().isObstacle() );
506
507 mObstacleSettings = mSettings.obstacleSettings();
508
509 mChkNoDuplicates->setChecked( mThinningSettings.allowDuplicateRemoval() );
510
511 mLineSettings = mSettings.lineSettings();
512
513 mComboMultipartBehavior->setCurrentIndex( mComboMultipartBehavior->findData( QVariant::fromValue( mSettings.placementSettings().multiPartBehavior() ) ) );
514
515 mComboOverlapHandling->setCurrentIndex( mComboOverlapHandling->findData( static_cast<int>( mSettings.placementSettings().overlapHandling() ) ) );
516 mCheckAllowDegradedPlacement->setChecked( mSettings.placementSettings().allowDegradedPlacement() );
517 mPrioritizationComboBox->setCurrentIndex( mPrioritizationComboBox->findData( QVariant::fromValue( mSettings.placementSettings().prioritization() ) ) );
518
519 mComboCurvedLabelMode->setCurrentIndex( mComboCurvedLabelMode->findData( QVariant::fromValue( mSettings.lineSettings().curvedLabelMode() ) ) );
520
521 mCheckWhitespaceIsNotACollision->setChecked( mSettings.placementSettings().whitespaceCollisionHandling() == Qgis::LabelWhitespaceCollisionHandling::IgnoreWhitespaceCollisions );
522
523 chkMergeLines->setChecked( mSettings.lineSettings().mergeLines() );
524 mMinSizeSpinBox->setValue( mThinningSettings.minimumFeatureSize() );
525 mLimitLabelChkBox->setChecked( mThinningSettings.limitNumberOfLabelsEnabled() );
526 mLimitLabelSpinBox->setValue( mThinningSettings.maximumNumberLabels() );
527
528 // direction symbol(s)
529 mDirectSymbChkBx->setChecked( mSettings.lineSettings().addDirectionSymbol() );
530 mDirectSymbLeftLineEdit->setText( mSettings.lineSettings().leftDirectionSymbol() );
531 mDirectSymbRightLineEdit->setText( mSettings.lineSettings().rightDirectionSymbol() );
532 mDirectSymbRevChkBx->setChecked( mSettings.lineSettings().reverseDirectionSymbol() );
533
534 mDirectSymbBtnGrp->button( static_cast<int>( mSettings.lineSettings().directionSymbolPlacement() ) )->setChecked( true );
535 mUpsidedownBtnGrp->button( static_cast<int>( mSettings.upsidedownLabels ) )->setChecked( true );
536
537 // curved label max character angles
538 mMaxCharAngleInDSpinBox->setValue( mSettings.maxCurvedCharAngleIn );
539 // lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
540 mMaxCharAngleOutDSpinBox->setValue( std::fabs( mSettings.maxCurvedCharAngleOut ) );
541
542 wrapCharacterEdit->setText( mSettings.wrapChar );
543 mAutoWrapLengthSpinBox->setValue( mSettings.autoWrapLength );
544 mAutoWrapTypeComboBox->setCurrentIndex( mSettings.useMaxLineLengthForAutoWrap ? 0 : 1 );
545
546 if ( mFontMultiLineAlignComboBox->findData( static_cast<int>( mSettings.multilineAlign ) ) != -1 )
547 {
548 mFontMultiLineAlignComboBox->setCurrentIndex( mFontMultiLineAlignComboBox->findData( static_cast<int>( mSettings.multilineAlign ) ) );
549 }
550 else
551 {
552 // the default pal layer settings for multiline alignment is to follow label placement, which isn't always available
553 // revert to left alignment in such case
554 mFontMultiLineAlignComboBox->setCurrentIndex( 0 );
555 }
556
557 chkPreserveRotation->setChecked( mSettings.preserveRotation );
558
559 mCoordRotationUnitComboBox->setCurrentIndex( 0 );
560 if ( mCoordRotationUnitComboBox->findData( static_cast<unsigned int>( mSettings.rotationUnit() ) ) >= 0 )
561 mCoordRotationUnitComboBox->setCurrentIndex( mCoordRotationUnitComboBox->findData( static_cast<unsigned int>( mSettings.rotationUnit() ) ) );
562
563 mScaleBasedVisibilityChkBx->setChecked( mSettings.scaleVisibility );
564 mMinScaleWidget->setScale( mSettings.minimumScale );
565 mMaxScaleWidget->setScale( mSettings.maximumScale );
566
567 mFormatNumChkBx->setChecked( mSettings.formatNumbers );
568 mFormatNumDecimalsSpnBx->setValue( mSettings.decimals );
569 mFormatNumPlusSignChkBx->setChecked( mSettings.plusSign );
570
571 // set pixel size limiting checked state before unit choice so limiting can be
572 // turned on as a default for map units, if minimum trigger value of 0 is used
573 mFontLimitPixelChkBox->setChecked( mSettings.fontLimitPixelSize );
574 mMinPixelLimit = mSettings.fontMinPixelSize; // ignored after first settings save
575 mFontMinPixelSpinBox->setValue( mSettings.fontMinPixelSize == 0 ? 3 : mSettings.fontMinPixelSize );
576 mFontMaxPixelSpinBox->setValue( mSettings.fontMaxPixelSize );
577
578 mZIndexSpinBox->setValue( mSettings.zIndex );
579
580 mDataDefinedProperties = mSettings.dataDefinedProperties();
581
582 // callout settings, to move to custom widget when multiple styles exist
583 if ( auto *lCallout = mSettings.callout() )
584 {
585 whileBlocking( mCalloutsDrawCheckBox )->setChecked( lCallout->enabled() );
586 whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( lCallout->type() ) );
587 updateCalloutWidget( lCallout );
588 }
589 else
590 {
591 std::unique_ptr<QgsCallout> defaultCallout( QgsCalloutRegistry::defaultCallout() );
592 whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( defaultCallout->type() ) );
593 whileBlocking( mCalloutsDrawCheckBox )->setChecked( false );
594 updateCalloutWidget( defaultCallout.get() );
595 }
596
597 updatePlacementWidgets();
598 updateLinePlacementOptions();
599
600 // needs to come before data defined setup, so connections work
601 blockInitSignals( false );
602
603 // set up data defined toolbuttons
604 // do this after other widgets are configured, so they can be enabled/disabled
605 populateDataDefinedButtons();
606
607 updateUi(); // should come after data defined button setup
608}
609
610void QgsLabelingGui::setSettings( const QgsPalLayerSettings &settings )
611{
612 mSettings = settings;
613 setLayer( mLayer );
614}
615
616void QgsLabelingGui::blockInitSignals( bool block )
617{
618 chkLineAbove->blockSignals( block );
619 chkLineBelow->blockSignals( block );
620 mPlacementModeComboBox->blockSignals( block );
621}
622
623void QgsLabelingGui::setLabelMode( LabelMode mode )
624{
625 mMode = mode;
626 mFieldExpressionWidget->setEnabled( mMode == Labels );
627 mLabelingFrame->setEnabled( mMode == Labels );
628}
629
630QgsPalLayerSettings QgsLabelingGui::layerSettings()
631{
632 QgsPalLayerSettings lyr;
633
634 // restore properties which aren't exposed in GUI
635 lyr.setUnplacedVisibility( mSettings.unplacedVisibility() );
636
637 lyr.drawLabels = ( mMode == Labels ) || !mLayer;
638
639 bool isExpression;
640 lyr.fieldName = mFieldExpressionWidget->currentField( &isExpression );
641 lyr.isExpression = isExpression;
642
643 lyr.dist = 0;
644
646 if ( mCheckAllowLabelsOutsidePolygons->isChecked() )
648 lyr.setPolygonPlacementFlags( polygonPlacementFlags );
649
650 lyr.centroidWhole = mCentroidRadioWhole->isChecked();
651 lyr.centroidInside = mCentroidInsideCheckBox->isChecked();
652 lyr.fitInPolygonOnly = mFitInsidePolygonCheckBox->isChecked();
653 lyr.dist = mLineDistanceSpnBx->value();
654 lyr.distUnits = mLineDistanceUnitWidget->unit();
655 lyr.distMapUnitScale = mLineDistanceUnitWidget->getMapUnitScale();
656
657 lyr.pointSettings().setMaximumDistance( mMaximumDistanceSpnBx->value() );
658 lyr.pointSettings().setMaximumDistanceUnit( mMaximumDistanceUnitWidget->unit() );
659 lyr.pointSettings().setMaximumDistanceMapUnitScale( mMaximumDistanceUnitWidget->getMapUnitScale() );
660
661 lyr.offsetType = static_cast<Qgis::LabelOffsetType>( mOffsetTypeComboBox->currentData().toInt() );
662 if ( mQuadrantBtnGrp )
663 {
664 lyr.pointSettings().setQuadrant( static_cast<Qgis::LabelQuadrantPosition>( mQuadrantBtnGrp->checkedId() ) );
665 }
666 lyr.xOffset = mPointOffsetXSpinBox->value();
667 lyr.yOffset = mPointOffsetYSpinBox->value();
668 lyr.offsetUnits = mPointOffsetUnitWidget->unit();
669 lyr.labelOffsetMapUnitScale = mPointOffsetUnitWidget->getMapUnitScale();
670 lyr.angleOffset = mPointAngleSpinBox->value();
671
673 if ( chkLineAbove->isChecked() )
674 linePlacementFlags |= Qgis::LabelLinePlacementFlag::AboveLine;
675 if ( chkLineBelow->isChecked() )
676 linePlacementFlags |= Qgis::LabelLinePlacementFlag::BelowLine;
677 if ( chkLineOn->isChecked() )
678 linePlacementFlags |= Qgis::LabelLinePlacementFlag::OnLine;
679 if ( !chkLineOrientationDependent->isChecked() )
681 lyr.lineSettings().setPlacementFlags( linePlacementFlags );
682
683 lyr.placement = static_cast<Qgis::LabelPlacement>( mPlacementModeComboBox->currentData().toInt() );
684
685 lyr.repeatDistance = mRepeatDistanceSpinBox->value();
686 lyr.repeatDistanceUnit = mRepeatDistanceUnitWidget->unit();
687 lyr.repeatDistanceMapUnitScale = mRepeatDistanceUnitWidget->getMapUnitScale();
688
689 lyr.lineSettings().setOverrunDistance( mOverrunDistanceSpinBox->value() );
690 lyr.lineSettings().setOverrunDistanceUnit( mOverrunDistanceUnitWidget->unit() );
691 lyr.lineSettings().setOverrunDistanceMapUnitScale( mOverrunDistanceUnitWidget->getMapUnitScale() );
692
693 mThinningSettings.setLabelMarginDistance( mLabelMarginSpinBox->value() );
694 mThinningSettings.setLabelMarginDistanceUnit( mLabelMarginUnitWidget->unit() );
695 mThinningSettings.setLabelMarginDistanceMapUnitScale( mLabelMarginUnitWidget->getMapUnitScale() );
696
697 lyr.priority = mPrioritySlider->value();
698
699 mObstacleSettings.setIsObstacle( mChkNoObstacle->isChecked() || mMode == ObstaclesOnly );
700 lyr.setObstacleSettings( mObstacleSettings );
701
702 lyr.lineSettings().setLineAnchorPercent( mLineSettings.lineAnchorPercent() );
703 lyr.lineSettings().setAnchorType( mLineSettings.anchorType() );
704 lyr.lineSettings().setAnchorClipping( mLineSettings.anchorClipping() );
705 lyr.lineSettings().setAnchorTextPoint( mLineSettings.anchorTextPoint() );
706
707 mThinningSettings.setAllowDuplicateRemoval( mChkNoDuplicates->isChecked() );
708
709 lyr.placementSettings().setMultiPartBehavior( mComboMultipartBehavior->currentData().value< Qgis::MultiPartLabelingBehavior >() );
710 lyr.placementSettings().setOverlapHandling( static_cast<Qgis::LabelOverlapHandling>( mComboOverlapHandling->currentData().toInt() ) );
711 lyr.placementSettings().setAllowDegradedPlacement( mCheckAllowDegradedPlacement->isChecked() );
712 lyr.placementSettings().setPrioritization( mPrioritizationComboBox->currentData().value<Qgis::LabelPrioritization>() );
714
715 lyr.lineSettings().setMergeLines( chkMergeLines->isChecked() );
716 lyr.lineSettings().setCurvedLabelMode( mComboCurvedLabelMode->currentData().value< Qgis::CurvedLabelMode >() );
717
718 lyr.scaleVisibility = mScaleBasedVisibilityChkBx->isChecked();
719 lyr.minimumScale = mMinScaleWidget->scale();
720 lyr.maximumScale = mMaxScaleWidget->scale();
721 lyr.useSubstitutions = mCheckBoxSubstituteText->isChecked();
722 lyr.substitutions = mSubstitutions;
723
724 lyr.setFormat( format( false ) );
725
726 // format numbers
727 lyr.formatNumbers = mFormatNumChkBx->isChecked();
728 lyr.decimals = mFormatNumDecimalsSpnBx->value();
729 lyr.plusSign = mFormatNumPlusSignChkBx->isChecked();
730
731 // direction symbol(s)
732 lyr.lineSettings().setAddDirectionSymbol( mDirectSymbChkBx->isChecked() );
733 lyr.lineSettings().setLeftDirectionSymbol( mDirectSymbLeftLineEdit->text() );
734 lyr.lineSettings().setRightDirectionSymbol( mDirectSymbRightLineEdit->text() );
735 lyr.lineSettings().setReverseDirectionSymbol( mDirectSymbRevChkBx->isChecked() );
736 if ( mDirectSymbBtnGrp )
737 {
738 lyr.lineSettings().setDirectionSymbolPlacement( static_cast<QgsLabelLineSettings::DirectionSymbolPlacement>( mDirectSymbBtnGrp->checkedId() ) );
739 }
740 if ( mUpsidedownBtnGrp )
741 {
742 lyr.upsidedownLabels = static_cast<Qgis::UpsideDownLabelHandling>( mUpsidedownBtnGrp->checkedId() );
743 }
744
745 lyr.maxCurvedCharAngleIn = mMaxCharAngleInDSpinBox->value();
746 // lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
747 lyr.maxCurvedCharAngleOut = -mMaxCharAngleOutDSpinBox->value();
748
749 mThinningSettings.setMinimumFeatureSize( mMinSizeSpinBox->value() );
750 mThinningSettings.setLimitNumberLabelsEnabled( mLimitLabelChkBox->isChecked() );
751 mThinningSettings.setMaximumNumberLabels( mLimitLabelSpinBox->value() );
752
753 lyr.setThinningSettings( mThinningSettings );
754
755 lyr.fontLimitPixelSize = mFontLimitPixelChkBox->isChecked();
756 lyr.fontMinPixelSize = mFontMinPixelSpinBox->value();
757 lyr.fontMaxPixelSize = mFontMaxPixelSpinBox->value();
758 lyr.wrapChar = wrapCharacterEdit->text();
759 lyr.autoWrapLength = mAutoWrapLengthSpinBox->value();
760 lyr.useMaxLineLengthForAutoWrap = mAutoWrapTypeComboBox->currentIndex() == 0;
761 lyr.multilineAlign = static_cast<Qgis::LabelMultiLineAlignment>( mFontMultiLineAlignComboBox->currentData().toInt() );
762 lyr.preserveRotation = chkPreserveRotation->isChecked();
763 lyr.setRotationUnit( static_cast<Qgis::AngleUnit>( mCoordRotationUnitComboBox->currentData().toInt() ) );
764 lyr.geometryGenerator = mGeometryGenerator->text();
765 lyr.geometryGeneratorType = mGeometryGeneratorType->currentData().value<Qgis::GeometryType>();
766 lyr.geometryGeneratorEnabled = mGeometryGeneratorGroupBox->isChecked();
767
768 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
769 lyr.layerType = vLayer ? vLayer->geometryType() : mGeomType;
770
771 lyr.zIndex = mZIndexSpinBox->value();
772
773 lyr.setDataDefinedProperties( mDataDefinedProperties );
774
775 // callout settings
776 const QString calloutType = mCalloutStyleComboBox->currentData().toString();
777 std::unique_ptr<QgsCallout> callout;
778 if ( QgsCalloutWidget *pew = qobject_cast<QgsCalloutWidget *>( mCalloutStackedWidget->currentWidget() ) )
779 {
780 callout.reset( pew->callout()->clone() );
781 }
782 if ( !callout )
783 callout.reset( QgsApplication::calloutRegistry()->createCallout( calloutType ) );
784
785 callout->setEnabled( mCalloutsDrawCheckBox->isChecked() );
786 lyr.setCallout( callout.release() );
787
788 return lyr;
789}
790
791void QgsLabelingGui::syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f )
792{
793 f->setEnabled( chkBx->isChecked() || ddBtn->isActive() );
794}
795
796bool QgsLabelingGui::eventFilter( QObject *object, QEvent *event )
797{
798 if ( object == mLblNoObstacle1 )
799 {
800 if ( event->type() == QEvent::MouseButtonPress && qgis::down_cast<QMouseEvent *>( event )->button() == Qt::LeftButton )
801 {
802 // clicking the obstacle label toggles the checkbox, just like a "normal" checkbox label...
803 mChkNoObstacle->setChecked( !mChkNoObstacle->isChecked() );
804 return true;
805 }
806 return false;
807 }
808 return QgsTextFormatWidget::eventFilter( object, event );
809}
810
811void QgsLabelingGui::updateUi()
812{
813 // enable/disable inline groupbox-like setups (that need to honor data defined setting)
814
815 syncDefinedCheckboxFrame( mBufferDrawDDBtn, mBufferDrawChkBx, mBufferFrame );
816 syncDefinedCheckboxFrame( mEnableMaskDDBtn, mEnableMaskChkBx, mMaskFrame );
817 syncDefinedCheckboxFrame( mShapeDrawDDBtn, mShapeDrawChkBx, mShapeFrame );
818 syncDefinedCheckboxFrame( mShadowDrawDDBtn, mShadowDrawChkBx, mShadowFrame );
819 syncDefinedCheckboxFrame( mCalloutDrawDDBtn, mCalloutsDrawCheckBox, mCalloutFrame );
820
821 syncDefinedCheckboxFrame( mDirectSymbDDBtn, mDirectSymbChkBx, mDirectSymbFrame );
822 syncDefinedCheckboxFrame( mFormatNumDDBtn, mFormatNumChkBx, mFormatNumFrame );
823 syncDefinedCheckboxFrame( mScaleBasedVisibilityDDBtn, mScaleBasedVisibilityChkBx, mScaleBasedVisibilityFrame );
824 syncDefinedCheckboxFrame( mFontLimitPixelDDBtn, mFontLimitPixelChkBox, mFontLimitPixelFrame );
825
826 chkMergeLines->setEnabled( !mDirectSymbChkBx->isChecked() );
827 if ( mDirectSymbChkBx->isChecked() )
828 {
829 chkMergeLines->setToolTip( tr( "This option is not compatible with line direction symbols." ) );
830 }
831 else
832 {
833 chkMergeLines->setToolTip( QString() );
834 }
835}
836
837void QgsLabelingGui::setFormatFromStyle( const QString &name, QgsStyle::StyleEntity type, const QString &stylePath )
838{
839 QgsStyle *style = QgsProject::instance()->styleSettings()->styleAtPath( stylePath );
840
841 if ( !style )
842 style = QgsStyle::defaultStyle();
843
844 switch ( type )
845 {
853 {
854 QgsTextFormatWidget::setFormatFromStyle( name, type, stylePath );
855 return;
856 }
857
859 {
860 if ( !style->labelSettingsNames().contains( name ) )
861 return;
862
863 QgsPalLayerSettings settings = style->labelSettings( name );
864 if ( settings.fieldName.isEmpty() )
865 {
866 // if saved settings doesn't have a field name stored, retain the current one
867 bool isExpression;
868 settings.fieldName = mFieldExpressionWidget->currentField( &isExpression );
869 settings.isExpression = isExpression;
870 }
871 setSettings( settings );
872 break;
873 }
874 }
875}
876
877void QgsLabelingGui::setContext( const QgsSymbolWidgetContext &context )
878{
879 if ( QgsCalloutWidget *cw = qobject_cast<QgsCalloutWidget *>( mCalloutStackedWidget->currentWidget() ) )
880 {
881 cw->setContext( context );
882 }
884}
885
886void QgsLabelingGui::saveFormat()
887{
888 QgsStyleSaveDialog saveDlg( this, QgsStyle::LabelSettingsEntity );
889 saveDlg.setDefaultTags( mTextFormatsListWidget->currentTagFilter() );
890 if ( !saveDlg.exec() )
891 return;
892
893 if ( saveDlg.name().isEmpty() )
894 return;
895
896 QgsStyle *style = saveDlg.destinationStyle();
897 if ( !style )
898 return;
899
900 switch ( saveDlg.selectedType() )
901 {
903 {
904 // check if there is no format with same name
905 if ( style->textFormatNames().contains( saveDlg.name() ) )
906 {
907 const int res = QMessageBox::warning( this, tr( "Save Text Format" ), tr( "Format with name '%1' already exists. Overwrite?" ).arg( saveDlg.name() ), QMessageBox::Yes | QMessageBox::No );
908 if ( res != QMessageBox::Yes )
909 {
910 return;
911 }
912 style->removeTextFormat( saveDlg.name() );
913 }
914 const QStringList symbolTags = saveDlg.tags().split( ',' );
915
916 const QgsTextFormat newFormat = format();
917 style->addTextFormat( saveDlg.name(), newFormat );
918 style->saveTextFormat( saveDlg.name(), newFormat, saveDlg.isFavorite(), symbolTags );
919 break;
920 }
921
923 {
924 // check if there is no settings with same name
925 if ( style->labelSettingsNames().contains( saveDlg.name() ) )
926 {
927 const int res = QMessageBox::warning( this, tr( "Save Label Settings" ), tr( "Label settings with the name '%1' already exist. Overwrite?" ).arg( saveDlg.name() ), QMessageBox::Yes | QMessageBox::No );
928 if ( res != QMessageBox::Yes )
929 {
930 return;
931 }
932 style->removeLabelSettings( saveDlg.name() );
933 }
934 const QStringList symbolTags = saveDlg.tags().split( ',' );
935
936 const QgsPalLayerSettings newSettings = layerSettings();
937 style->addLabelSettings( saveDlg.name(), newSettings );
938 style->saveLabelSettings( saveDlg.name(), newSettings, saveDlg.isFavorite(), symbolTags );
939 break;
940 }
941
948 break;
949 }
950}
951
952void QgsLabelingGui::updateGeometryTypeBasedWidgets()
953{
954 Qgis::GeometryType geometryType = mGeomType;
955
956 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
957
958 if ( mGeometryGeneratorGroupBox->isChecked() )
959 geometryType = mGeometryGeneratorType->currentData().value<Qgis::GeometryType>();
960 else if ( vLayer )
961 geometryType = vLayer->geometryType();
962
963 // show/hide options based upon geometry type
964 chkMergeLines->setVisible( geometryType == Qgis::GeometryType::Line );
965 mDirectSymbolsFrame->setVisible( geometryType == Qgis::GeometryType::Line );
966 mMinSizeFrame->setVisible( geometryType != Qgis::GeometryType::Point );
967 mPolygonFeatureOptionsFrame->setVisible( geometryType == Qgis::GeometryType::Polygon );
968
969
970 const Qgis::LabelPlacement prevPlacement = static_cast<Qgis::LabelPlacement>( mPlacementModeComboBox->currentData().toInt() );
971 mPlacementModeComboBox->clear();
972
973 switch ( geometryType )
974 {
976 mPlacementModeComboBox->addItem( tr( "Cartographic" ), static_cast<int>( Qgis::LabelPlacement::OrderedPositionsAroundPoint ) );
977 mPlacementModeComboBox->addItem( tr( "Around Point" ), static_cast<int>( Qgis::LabelPlacement::AroundPoint ) );
978 mPlacementModeComboBox->addItem( tr( "Offset from Point" ), static_cast<int>( Qgis::LabelPlacement::OverPoint ) );
979 break;
980
982 mPlacementModeComboBox->addItem( tr( "Parallel" ), static_cast<int>( Qgis::LabelPlacement::Line ) );
983 mPlacementModeComboBox->addItem( tr( "Curved" ), static_cast<int>( Qgis::LabelPlacement::Curved ) );
984 mPlacementModeComboBox->addItem( tr( "Horizontal" ), static_cast<int>( Qgis::LabelPlacement::Horizontal ) );
985 break;
986
988 mPlacementModeComboBox->addItem( tr( "Offset from Centroid" ), static_cast<int>( Qgis::LabelPlacement::OverPoint ) );
989 mPlacementModeComboBox->addItem( tr( "Around Centroid" ), static_cast<int>( Qgis::LabelPlacement::AroundPoint ) );
990 mPlacementModeComboBox->addItem( tr( "Horizontal" ), static_cast<int>( Qgis::LabelPlacement::Horizontal ) );
991 mPlacementModeComboBox->addItem( tr( "Free (Angled)" ), static_cast<int>( Qgis::LabelPlacement::Free ) );
992 mPlacementModeComboBox->addItem( tr( "Using Perimeter" ), static_cast<int>( Qgis::LabelPlacement::Line ) );
993 mPlacementModeComboBox->addItem( tr( "Using Perimeter (Curved)" ), static_cast<int>( Qgis::LabelPlacement::PerimeterCurved ) );
994 mPlacementModeComboBox->addItem( tr( "Outside Polygons" ), static_cast<int>( Qgis::LabelPlacement::OutsidePolygons ) );
995 break;
996
998 break;
1000 qFatal( "unknown geometry type unexpected" );
1001 }
1002
1003 if ( mPlacementModeComboBox->findData( static_cast<int>( prevPlacement ) ) != -1 )
1004 {
1005 mPlacementModeComboBox->setCurrentIndex( mPlacementModeComboBox->findData( static_cast<int>( prevPlacement ) ) );
1006 }
1007
1008 if ( geometryType == Qgis::GeometryType::Point || geometryType == Qgis::GeometryType::Polygon )
1009 {
1010 // follow placement alignment is only valid for point or polygon layers
1011 if ( mFontMultiLineAlignComboBox->findData( static_cast<int>( Qgis::LabelMultiLineAlignment::FollowPlacement ) ) == -1 )
1012 mFontMultiLineAlignComboBox->addItem( tr( "Follow Label Placement" ), static_cast<int>( Qgis::LabelMultiLineAlignment::FollowPlacement ) );
1013 }
1014 else
1015 {
1016 const int idx = mFontMultiLineAlignComboBox->findData( static_cast<int>( Qgis::LabelMultiLineAlignment::FollowPlacement ) );
1017 if ( idx >= 0 )
1018 mFontMultiLineAlignComboBox->removeItem( idx );
1019 }
1020
1021 updatePlacementWidgets();
1022 updateLinePlacementOptions();
1023}
1024
1025void QgsLabelingGui::showGeometryGeneratorExpressionBuilder()
1026{
1027 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
1028 QgsExpressionBuilderDialog expressionBuilder( vLayer );
1029
1030 expressionBuilder.setExpressionText( mGeometryGenerator->text() );
1031 expressionBuilder.setExpressionContext( createExpressionContext() );
1032
1033 if ( expressionBuilder.exec() )
1034 {
1035 mGeometryGenerator->setText( expressionBuilder.expressionText() );
1036 }
1037}
1038
1039void QgsLabelingGui::validateGeometryGeneratorExpression()
1040{
1041 bool valid = true;
1042
1043 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
1044
1045 if ( mGeometryGeneratorGroupBox->isChecked() )
1046 {
1047 if ( !mPreviewFeature.isValid() && vLayer )
1048 vLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
1049
1050 QgsExpression expression( mGeometryGenerator->text() );
1051 QgsExpressionContext context = createExpressionContext();
1052 context.setFeature( mPreviewFeature );
1053
1054 expression.prepare( &context );
1055
1056 if ( expression.hasParserError() )
1057 {
1058 mGeometryGeneratorWarningLabel->setText( expression.parserErrorString() );
1059 valid = false;
1060 }
1061 else
1062 {
1063 const QVariant result = expression.evaluate( &context );
1064 const QgsGeometry geometry = result.value<QgsGeometry>();
1065 const Qgis::GeometryType configuredGeometryType = mGeometryGeneratorType->currentData().value<Qgis::GeometryType>();
1066 if ( geometry.isNull() )
1067 {
1068 mGeometryGeneratorWarningLabel->setText( tr( "Result of the expression is not a geometry" ) );
1069 valid = false;
1070 }
1071 else if ( geometry.type() != configuredGeometryType )
1072 {
1073 mGeometryGeneratorWarningLabel->setText( u"<p>%1</p><p><a href=\"#determineGeometryGeneratorType\">%2</a></p>"_s.arg( tr( "Result of the expression does not match configured geometry type." ), tr( "Change to %1" ).arg( QgsWkbTypes::geometryDisplayString( geometry.type() ) ) ) );
1074 valid = false;
1075 }
1076 }
1077 }
1078
1079 // The collapsible groupbox internally changes the visibility of this
1080 // Work around by setting the visibility deferred in the next event loop cycle.
1081 QTimer *timer = new QTimer();
1082 connect( timer, &QTimer::timeout, this, [this, valid]() {
1083 mGeometryGeneratorWarningLabel->setVisible( !valid );
1084 } );
1085 connect( timer, &QTimer::timeout, timer, &QTimer::deleteLater );
1086 timer->start( 0 );
1087}
1088
1089void QgsLabelingGui::determineGeometryGeneratorType()
1090{
1091 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer );
1092 if ( !mPreviewFeature.isValid() && vLayer )
1093 vLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
1094
1095 QgsExpression expression( mGeometryGenerator->text() );
1096 QgsExpressionContext context = createExpressionContext();
1097 context.setFeature( mPreviewFeature );
1098
1099 expression.prepare( &context );
1100 const QgsGeometry geometry = expression.evaluate( &context ).value<QgsGeometry>();
1101
1102 mGeometryGeneratorType->setCurrentIndex( mGeometryGeneratorType->findData( QVariant::fromValue( geometry.type() ) ) );
1103}
1104
1105void QgsLabelingGui::calloutTypeChanged()
1106{
1107 const QString newCalloutType = mCalloutStyleComboBox->currentData().toString();
1108 QgsCalloutWidget *pew = qobject_cast<QgsCalloutWidget *>( mCalloutStackedWidget->currentWidget() );
1109 if ( pew )
1110 {
1111 if ( pew->callout() && pew->callout()->type() == newCalloutType )
1112 return;
1113 }
1114
1115 // get creation function for new callout from registry
1116 QgsCalloutRegistry *registry = QgsApplication::calloutRegistry();
1117 QgsCalloutAbstractMetadata *am = registry->calloutMetadata( newCalloutType );
1118 if ( !am ) // check whether the metadata is assigned
1119 return;
1120
1121 // change callout to a new one (with different type)
1122 // base new callout on existing callout's properties
1123 const std::unique_ptr<QgsCallout> newCallout( am->createCallout( pew && pew->callout() ? pew->callout()->properties( QgsReadWriteContext() ) : QVariantMap(), QgsReadWriteContext() ) );
1124 if ( !newCallout )
1125 return;
1126
1127 updateCalloutWidget( newCallout.get() );
1128 updatePreview();
1129}
1130
1131
1132//
1133// QgsLabelSettingsDialog
1134//
1135
1136QgsLabelSettingsDialog::QgsLabelSettingsDialog( const QgsPalLayerSettings &settings, QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, QWidget *parent, Qgis::GeometryType geomType )
1137 : QDialog( parent )
1138{
1139 QVBoxLayout *vLayout = new QVBoxLayout();
1140 mWidget = new QgsLabelingGui( layer, mapCanvas, settings, nullptr, geomType );
1141 vLayout->addWidget( mWidget );
1142 mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok, Qt::Horizontal );
1143 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
1144 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
1145 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsLabelSettingsDialog::showHelp );
1146 vLayout->addWidget( mButtonBox );
1147 setLayout( vLayout );
1148 setWindowTitle( tr( "Label Settings" ) );
1149}
1150
1151QDialogButtonBox *QgsLabelSettingsDialog::buttonBox() const
1152{
1153 return mButtonBox;
1154}
1155
1156void QgsLabelSettingsDialog::showHelp()
1157{
1158 QgsHelp::openHelp( u"style_library/label_settings.html"_s );
1159}
1160
1161
CurvedLabelMode
Modes which determine how curved labels are generated and placed.
Definition qgis.h:1244
MultiPartLabelingBehavior
Behavior modifier for labeling features with multi-part geometries.
Definition qgis.h:1283
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
Definition qgis.h:1336
@ MapOrientation
Signifies that the AboveLine and BelowLine flags should respect the map's orientation rather than the...
Definition qgis.h:1337
@ OnLine
Labels can be placed directly over a line feature.
Definition qgis.h:1334
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
Definition qgis.h:1335
AngleUnit
Units of angles.
Definition qgis.h:5245
@ SecondsOfArc
Seconds of arc.
Definition qgis.h:5250
@ Radians
Square kilometers.
Definition qgis.h:5247
@ Turn
Turn/revolutions.
Definition qgis.h:5251
@ MinutesOfArc
Minutes of arc.
Definition qgis.h:5249
@ MilliradiansSI
Angular milliradians (SI definition, 1/1000 of radian).
Definition qgis.h:5252
@ Degrees
Degrees.
Definition qgis.h:5246
@ Gon
Gon/gradian.
Definition qgis.h:5248
@ MilNATO
Angular mil (NATO definition, 6400 mil = 2PI radians).
Definition qgis.h:5253
LabelOffsetType
Behavior modifier for label offset and distance, only applies in some label placement modes.
Definition qgis.h:1299
LabelPrioritization
Label prioritization.
Definition qgis.h:1211
LabelPlacement
Placement modes which determine how label candidates are generated for a feature.
Definition qgis.h:1225
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
Definition qgis.h:1227
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
Definition qgis.h:1229
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
Definition qgis.h:1226
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
Definition qgis.h:1228
@ Free
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
Definition qgis.h:1231
@ OrderedPositionsAroundPoint
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
Definition qgis.h:1232
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
Definition qgis.h:1230
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
Definition qgis.h:1233
@ OutsidePolygons
Candidates are placed outside of polygon boundaries. Applies to polygon layers only.
Definition qgis.h:1234
@ AllowPlacementInsideOfPolygon
Labels can be placed inside a polygon feature.
Definition qgis.h:1360
@ AllowPlacementOutsideOfPolygon
Labels can be placed outside of a polygon feature.
Definition qgis.h:1359
QFlags< LabelLinePlacementFlag > LabelLinePlacementFlags
Line placement flags, which control how candidates are generated for a linear feature.
Definition qgis.h:1348
QFlags< LabelPolygonPlacementFlag > LabelPolygonPlacementFlags
Polygon placement flags, which control how candidates are generated for a polygon feature.
Definition qgis.h:1370
LabelQuadrantPosition
Label quadrant positions.
Definition qgis.h:1313
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:365
@ Point
Points.
Definition qgis.h:366
@ Line
Lines.
Definition qgis.h:367
@ Polygon
Polygons.
Definition qgis.h:368
@ Unknown
Unknown types.
Definition qgis.h:369
@ Null
No geometry.
Definition qgis.h:370
LabelMultiLineAlignment
Text alignment for multi-line labels.
Definition qgis.h:1396
@ Center
Center align.
Definition qgis.h:1398
@ FollowPlacement
Alignment follows placement of label, e.g., labels to the left of a feature will be drawn with right ...
Definition qgis.h:1400
@ Vector
Vector layer.
Definition qgis.h:194
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:197
@ TreatWhitespaceAsCollision
Treat overlapping whitespace text in labels and whitespace overlapping obstacles as collisions.
Definition qgis.h:1200
@ IgnoreWhitespaceCollisions
Ignore overlapping whitespace text in labels and whitespace overlapping obstacles.
Definition qgis.h:1201
LabelOverlapHandling
Label overlap handling.
Definition qgis.h:1186
UpsideDownLabelHandling
Handling techniques for upside down labels.
Definition qgis.h:1381
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsCalloutRegistry * calloutRegistry()
Returns the application's callout registry, used for managing callout types.
virtual QgsCallout * createCallout(const QVariantMap &properties, const QgsReadWriteContext &context)=0
Create a callout of this type given the map of properties.
QgsCalloutAbstractMetadata * calloutMetadata(const QString &type) const
Returns the metadata for specified the specified callout type.
static QgsCallout * defaultCallout()
Create a new instance of a callout with default settings.
QStringList calloutTypes() const
Returns a list of all available callout types.
virtual QgsCallout * callout()=0
Returns the callout defined by the current settings in the widget.
void changed()
Should be emitted whenever configuration changes happened on this symbol layer configuration.
Abstract base class for callout renderers.
Definition qgscallout.h:55
virtual QString type() const =0
Returns a unique string representing the callout type.
virtual QVariantMap properties(const QgsReadWriteContext &context) const
Returns the properties describing the callout encoded in a string format.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
static QgsExpressionContextScope * meshExpressionScope(QgsMesh::ElementType elementType)
Creates a new scope which contains functions relating to mesh layer element elementType.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
static const QString EXPR_SYMBOL_COLOR
Inbuilt variable name for symbol color variable.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user.
static const QString EXPR_ORIGINAL_VALUE
Inbuilt variable name for value original value variable.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Qgis::GeometryType type
static void initCalloutWidgets()
Initializes callout widgets.
Definition qgsgui.cpp:431
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:41
void updateDataDefinedProperties(QgsPropertyCollection &properties) override
Updates a data defined properties collection, correctly setting the values for any properties related...
QgsLabelLineSettings settings() const
Returns the line settings defined by the widget.
void setSettings(const QgsLabelLineSettings &settings)
Sets the line settings to show in the widget.
void setPlacementFlags(Qgis::LabelLinePlacementFlags flags)
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
void setLineAnchorPercent(double percent)
Sets the percent along the line at which labels should be placed.
void setDirectionSymbolPlacement(DirectionSymbolPlacement placement)
Sets the placement for direction symbols.
AnchorType anchorType() const
Returns the line anchor type, which dictates how the lineAnchorPercent() setting is handled.
void setAnchorTextPoint(AnchorTextPoint point)
Sets the line anchor text point, which dictates which part of the label text should be placed at the ...
void setLeftDirectionSymbol(const QString &symbol)
Sets the string to use for left direction arrows.
AnchorTextPoint anchorTextPoint() const
Returns the line anchor text point, which dictates which part of the label text should be placed at t...
void setMergeLines(bool merge)
Sets whether connected line features with identical label text should be merged prior to generating l...
DirectionSymbolPlacement
Placement options for direction symbols.
void setRightDirectionSymbol(const QString &symbol)
Sets the string to use for right direction arrows.
void setAnchorClipping(AnchorClipping clipping)
Sets the line anchor clipping mode, which dictates how line strings are clipped before calculating th...
void setOverrunDistanceMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for label overrun distance.
double lineAnchorPercent() const
Returns the percent along the line at which labels should be placed.
void setAnchorType(AnchorType type)
Sets the line anchor type, which dictates how the lineAnchorPercent() setting is handled.
void setOverrunDistanceUnit(const Qgis::RenderUnit &unit)
Sets the unit for label overrun distance.
void setOverrunDistance(double distance)
Sets the distance which labels are allowed to overrun past the start or end of line features.
AnchorClipping anchorClipping() const
Returns the line anchor clipping mode, which dictates how line strings are clipped before calculating...
void setReverseDirectionSymbol(bool reversed)
Sets whether the direction symbols should be reversed.
void setAddDirectionSymbol(bool enabled)
Sets whether '<' or '>' (or custom strings set via leftDirectionSymbol and rightDirectionSymbol) will...
void setCurvedLabelMode(Qgis::CurvedLabelMode mode)
Sets the mode which determine how curved labels are generated and placed.
void setGeometryType(Qgis::GeometryType type) override
Sets the geometry type of the features to customize the widget accordingly.
QgsLabelObstacleSettings settings() const
Returns the obstacle settings defined by the widget.
void updateDataDefinedProperties(QgsPropertyCollection &properties) override
Updates a data defined properties collection, correctly setting the values for any properties related...
void setSettings(const QgsLabelObstacleSettings &settings)
Sets the obstacle settings to show in the widget.
void setOverlapHandling(Qgis::LabelOverlapHandling handling)
Sets the technique used to handle overlapping labels.
void setMultiPartBehavior(Qgis::MultiPartLabelingBehavior behavior)
Sets the multipart labeling behavior.
void setPrioritization(Qgis::LabelPrioritization prioritization)
Sets the technique used to prioritize labels.
void setAllowDegradedPlacement(bool allow)
Sets whether labels can be placed in inferior fallback positions if they cannot otherwise be placed.
void setWhitespaceCollisionHandling(Qgis::LabelWhitespaceCollisionHandling handling)
Sets the whitespace collision handling.
void setMaximumDistance(double distance)
Sets the maximum distance which labels are allowed to be from their corresponding points.
void setMaximumDistanceMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for label maximum distance.
void setQuadrant(Qgis::LabelQuadrantPosition quadrant)
Sets the quadrant in which to offset labels from the point.
void setMaximumDistanceUnit(Qgis::RenderUnit unit)
Sets the unit for label maximum distance.
void setSettings(const QgsLabelThinningSettings &settings)
Sets the thinning settings to show in the widget.
QgsLabelThinningSettings settings() const
Returns the thinning settings defined by the widget.
void updateDataDefinedProperties(QgsPropertyCollection &properties) override
Updates a data defined properties collection, correctly setting the values for any properties related...
void setGeometryType(Qgis::GeometryType type) override
Sets the geometry type of the features to customize the widget accordingly.
void changed()
Emitted when any of the settings described by the widget are changed.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
virtual void setGeometryType(Qgis::GeometryType type)
Sets the geometry type of the features to customize the widget accordingly.
void setDataDefinedProperties(const QgsPropertyCollection &dataDefinedProperties)
Sets the current data defined properties to show in the widget.
QgsPropertyCollection dataDefinedProperties() const
Returns the current data defined properties state as specified in the widget.
Map canvas is a class for displaying all GIS data types on a canvas.
Base class for all map layer types.
Definition qgsmaplayer.h:83
Qgis::LayerType type
Definition qgsmaplayer.h:93
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Contains settings for how a map layer will be labeled.
bool fitInPolygonOnly
true if only labels which completely fit within a polygon are allowed.
double yOffset
Vertical offset of label.
QgsMapUnitScale labelOffsetMapUnitScale
Map unit scale for label offset.
int fontMaxPixelSize
Maximum pixel size for showing rendered map unit labels (1 - 10000).
void setObstacleSettings(const QgsLabelObstacleSettings &settings)
Sets the label obstacle settings.
const QgsLabelPlacementSettings & placementSettings() const
Returns the label placement settings.
double maxCurvedCharAngleIn
Maximum angle between inside curved label characters (valid range 20.0 to 60.0).
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
double zIndex
Z-Index of label, where labels with a higher z-index are rendered on top of labels with a lower z-ind...
void setPolygonPlacementFlags(Qgis::LabelPolygonPlacementFlags flags)
Sets the polygon placement flags, which dictate how polygon labels can be placed.
QString wrapChar
Wrapping character string.
Qgis::LabelOffsetType offsetType
Offset type for layer (only applies in certain placement modes).
double xOffset
Horizontal offset of label.
Qgis::LabelPlacement placement
Label placement mode.
bool drawLabels
Whether to draw labels for this layer.
bool fontLimitPixelSize
true if label sizes should be limited by pixel size.
double minimumScale
The minimum map scale (i.e.
bool scaleVisibility
Set to true to limit label visibility to a range of scales.
double repeatDistance
Distance for repeating labels for a single feature.
bool geometryGeneratorEnabled
Defines if the geometry generator is enabled or not. If disabled, the standard geometry will be taken...
Qgis::LabelMultiLineAlignment multilineAlign
Horizontal alignment of multi-line labels.
bool centroidInside
true if centroid positioned labels must be placed inside their corresponding feature polygon,...
int priority
Label priority.
Qgis::GeometryType geometryGeneratorType
The type of the result geometry of the geometry generator.
int fontMinPixelSize
Minimum pixel size for showing rendered map unit labels (1 - 1000).
double angleOffset
Label rotation, in degrees clockwise.
double maxCurvedCharAngleOut
Maximum angle between outside curved label characters (valid range -20.0 to -95.0).
Qgis::GeometryType layerType
Geometry type of layers associated with these settings.
void setThinningSettings(const QgsLabelThinningSettings &settings)
Sets the label thinning settings.
Qgis::RenderUnit offsetUnits
Units for offsets of label.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the label's property collection, used for data defined overrides.
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
bool preserveRotation
True if label rotation should be preserved during label pin/unpin operations.
bool plusSign
Whether '+' signs should be prepended to positive numeric labels.
QString geometryGenerator
The geometry generator expression. Null if disabled.
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
QgsMapUnitScale distMapUnitScale
Map unit scale for label feature distance.
QgsStringReplacementCollection substitutions
Substitution collection for automatic text substitution with labels.
int decimals
Number of decimal places to show for numeric labels.
double dist
Distance from feature to the label.
void setRotationUnit(Qgis::AngleUnit angleUnit)
Set unit for rotation of labels.
QgsMapUnitScale repeatDistanceMapUnitScale
Map unit scale for repeating labels for a single feature.
Qgis::RenderUnit distUnits
Units the distance from feature to the label.
bool centroidWhole
true if feature centroid should be calculated from the whole feature, or false if only the visible pa...
Qgis::RenderUnit repeatDistanceUnit
Units for repeating labels for a single feature.
Qgis::UpsideDownLabelHandling upsidedownLabels
Controls whether upside down labels are displayed and how they are handled.
QString fieldName
Name of field (or an expression) to use for label text.
bool formatNumbers
Set to true to format numeric label text as numbers (e.g.
void setCallout(QgsCallout *callout)
Sets the label callout renderer, responsible for drawing label callouts.
double maximumScale
The maximum map scale (i.e.
int autoWrapLength
If non-zero, indicates that label text should be automatically wrapped to (ideally) the specified num...
bool useMaxLineLengthForAutoWrap
If true, indicates that when auto wrapping label text the autoWrapLength length indicates the maximum...
void setUnplacedVisibility(Qgis::UnplacedLabelVisibility visibility)
Sets the layer's unplaced label visibility.
const QgsLabelPointSettings & pointSettings() const
Returns the label point settings, which contain settings related to how the label engine places and f...
bool useSubstitutions
True if substitutions should be applied.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
bool dockMode() const
Returns the dock mode state.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
QgsStyle * styleAtPath(const QString &path)
Returns a reference to the style database associated with the project with matching file path.
static QgsProject * instance()
Returns the QgsProject singleton instance.
const QgsProjectStyleSettings * styleSettings() const
Returns the project's style settings, which contains settings and properties relating to how a QgsPro...
QgsCoordinateTransformContext transformContext
Definition qgsproject.h:120
A button for controlling property overrides which may apply to a widget.
bool isActive() const
Returns true if the button has an active property.
void changed()
Emitted when property definition changes.
@ CurrentPageOnly
Only the size of the current page is considered when calculating the stacked widget size.
bool removeLabelSettings(const QString &name)
Removes label settings from the style.
bool saveLabelSettings(const QString &name, const QgsPalLayerSettings &settings, bool favorite, const QStringList &tags)
Adds label settings to the database.
QStringList textFormatNames() const
Returns a list of names of text formats in the style.
bool removeTextFormat(const QString &name)
Removes a text format from the style.
StyleEntity
Enum for Entities involved in a style.
Definition qgsstyle.h:205
@ LabelSettingsEntity
Label settings.
Definition qgsstyle.h:211
@ TextFormatEntity
Text formats.
Definition qgsstyle.h:210
@ SmartgroupEntity
Smart groups.
Definition qgsstyle.h:209
@ Symbol3DEntity
3D symbol entity
Definition qgsstyle.h:213
@ SymbolEntity
Symbols.
Definition qgsstyle.h:206
@ TagEntity
Tags.
Definition qgsstyle.h:207
@ ColorrampEntity
Color ramps.
Definition qgsstyle.h:208
@ LegendPatchShapeEntity
Legend patch shape.
Definition qgsstyle.h:212
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:150
QStringList labelSettingsNames() const
Returns a list of names of label settings in the style.
static QgsTextFormat defaultTextFormatForProject(QgsProject *project, QgsStyle::TextFormatContext context=QgsStyle::TextFormatContext::Labeling)
Returns the default text format to use for new text based objects for the specified project,...
bool addTextFormat(const QString &name, const QgsTextFormat &format, bool update=false)
Adds a text format with the specified name to the style.
Definition qgsstyle.cpp:373
QgsPalLayerSettings labelSettings(const QString &name) const
Returns the label settings with the specified name.
@ Labeling
Text format used in labeling.
Definition qgsstyle.h:813
bool saveTextFormat(const QString &name, const QgsTextFormat &format, bool favorite, const QStringList &tags)
Adds a text format to the database.
Definition qgsstyle.cpp:978
bool addLabelSettings(const QString &name, const QgsPalLayerSettings &settings, bool update=false)
Adds label settings with the specified name to the style.
Definition qgsstyle.cpp:395
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void setExpressionContext(QgsExpressionContext *context)
Sets the optional expression context used for the widget.
A widget for customizing text formatting settings.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
virtual void setFormatFromStyle(const QString &name, QgsStyle::StyleEntity type, const QString &stylePath)
Sets the current text settings from a style entry.
static Q_INVOKABLE QString toString(Qgis::DistanceUnit unit)
Returns a translated string representing a distance unit.
Represents a vector layer which manages a vector based dataset.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
Implements a map layer that is dedicated to rendering of vector tiles.
static Q_INVOKABLE QString geometryDisplayString(Qgis::GeometryType type)
Returns a display string for a geometry type.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:6839