QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 #include "qgsvectorlayer.h"
20 #include "qgsmapcanvas.h"
21 #include "qgsvectorlayerlabeling.h"
22 #include "qgsproject.h"
23 #include "qgsauxiliarystorage.h"
27 #include "qgshelp.h"
28 #include "qgsstylesavedialog.h"
29 #include "qgscallout.h"
30 #include "qgsapplication.h"
31 #include "qgscalloutsregistry.h"
33 #include <mutex>
34 
35 #include <QButtonGroup>
36 #include <QMessageBox>
37 
39 
40 QgsExpressionContext QgsLabelingGui::createExpressionContext() const
41 {
42  QgsExpressionContext expContext;
46  if ( mCanvas )
47  expContext << QgsExpressionContextUtils::mapSettingsScope( mCanvas->mapSettings() );
48 
49  if ( mLayer )
50  expContext << QgsExpressionContextUtils::layerScope( mLayer );
51 
53 
54  //TODO - show actual value
55  expContext.setOriginalValueVariable( QVariant() );
57 
58  return expContext;
59 }
60 
61 static bool _initCalloutWidgetFunction( const QString &name, QgsCalloutWidgetFunc f )
62 {
64 
65  QgsCalloutAbstractMetadata *abstractMetadata = registry->calloutMetadata( name );
66  if ( !abstractMetadata )
67  {
68  QgsDebugMsg( QStringLiteral( "Failed to find callout entry in registry: %1" ).arg( name ) );
69  return false;
70  }
71  QgsCalloutMetadata *metadata = dynamic_cast<QgsCalloutMetadata *>( abstractMetadata );
72  if ( !metadata )
73  {
74  QgsDebugMsg( QStringLiteral( "Failed to cast callout's metadata: " ) .arg( name ) );
75  return false;
76  }
77  metadata->setWidgetFunction( f );
78  return true;
79 }
80 
81 void QgsLabelingGui::initCalloutWidgets()
82 {
83  _initCalloutWidgetFunction( QStringLiteral( "simple" ), QgsSimpleLineCalloutWidget::create );
84  _initCalloutWidgetFunction( QStringLiteral( "manhattan" ), QgsManhattanLineCalloutWidget::create );
85 }
86 
87 void QgsLabelingGui::updateCalloutWidget( QgsCallout *callout )
88 {
89  if ( !callout )
90  {
91  mCalloutStackedWidget->setCurrentWidget( pageDummy );
92  return;
93  }
94 
95  if ( mCalloutStackedWidget->currentWidget() != pageDummy )
96  {
97  // stop updating from the original widget
98  if ( QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
99  disconnect( pew, &QgsCalloutWidget::changed, this, &QgsLabelingGui::updatePreview );
100  }
101 
103  if ( QgsCalloutAbstractMetadata *am = registry->calloutMetadata( callout->type() ) )
104  {
105  if ( QgsCalloutWidget *w = am->createCalloutWidget( mLayer ) )
106  {
107 
108  QgsWkbTypes::GeometryType geometryType = mGeomType;
109  if ( mGeometryGeneratorGroupBox->isChecked() )
110  geometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
111  else if ( mLayer )
112  geometryType = mLayer->geometryType();
113  w->setGeometryType( geometryType );
114  w->setCallout( callout );
115 
116  w->setContext( context() );
117  mCalloutStackedWidget->addWidget( w );
118  mCalloutStackedWidget->setCurrentWidget( w );
119  // start receiving updates from widget
120  connect( w, &QgsCalloutWidget::changed, this, &QgsLabelingGui::updatePreview );
121  return;
122  }
123  }
124  // When anything is not right
125  mCalloutStackedWidget->setCurrentWidget( pageDummy );
126 }
127 
128 QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsPalLayerSettings &layerSettings, QWidget *parent, QgsWkbTypes::GeometryType geomType )
129  : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, layer )
130  , mGeomType( geomType )
131  , mSettings( layerSettings )
132  , mMode( NoLabels )
133  , mCanvas( mapCanvas )
134 {
135  static std::once_flag initialized;
136  std::call_once( initialized, [ = ]( )
137  {
138  initCalloutWidgets();
139  } );
140 
141  // connections for groupboxes with separate activation checkboxes (that need to honor data defined setting)
142  connect( mBufferDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
143  connect( mShapeDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
144  connect( mShadowDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
145  connect( mDirectSymbChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
146  connect( mFormatNumChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
147  connect( mScaleBasedVisibilityChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
148  connect( mFontLimitPixelChkBox, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
149  connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
150  connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
151  connect( mGeometryGeneratorExpressionButton, &QToolButton::clicked, this, &QgsLabelingGui::showGeometryGeneratorExpressionBuilder );
152  connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
153  connect( mGeometryGenerator, &QgsCodeEditorExpression::textChanged, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
154  connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::validateGeometryGeneratorExpression );
155 
156  mFieldExpressionWidget->registerExpressionContextGenerator( this );
157 
158  mMinScaleWidget->setMapCanvas( mCanvas );
159  mMinScaleWidget->setShowCurrentScaleButton( true );
160  mMaxScaleWidget->setMapCanvas( mCanvas );
161  mMaxScaleWidget->setShowCurrentScaleButton( true );
162 
163  const QStringList calloutTypes = QgsApplication::calloutRegistry()->calloutTypes();
164  for ( const QString &type : calloutTypes )
165  {
166  mCalloutStyleComboBox->addItem( QgsApplication::calloutRegistry()->calloutMetadata( type )->icon(),
167  QgsApplication::calloutRegistry()->calloutMetadata( type )->visibleName(), type );
168  }
169 
170  mGeometryGeneratorWarningLabel->setStyleSheet( QStringLiteral( "color: #FFC107;" ) );
171  mGeometryGeneratorWarningLabel->setTextInteractionFlags( Qt::TextBrowserInteraction );
172  connect( mGeometryGeneratorWarningLabel, &QLabel::linkActivated, this, [this]( const QString & link )
173  {
174  if ( link == QLatin1String( "#determineGeometryGeneratorType" ) )
175  determineGeometryGeneratorType();
176  } );
177 
178  connect( mCalloutStyleComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::calloutTypeChanged );
179 
180  setLayer( layer );
181 }
182 
183 void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
184 {
185  mPreviewFeature = QgsFeature();
186 
187  if ( ( !mapLayer || mapLayer->type() != QgsMapLayerType::VectorLayer ) && mGeomType == QgsWkbTypes::UnknownGeometry )
188  {
189  setEnabled( false );
190  return;
191  }
192 
193  setEnabled( true );
194 
195  QgsVectorLayer *layer = static_cast<QgsVectorLayer *>( mapLayer );
196  mLayer = layer;
197 
198  mTextFormatsListWidget->setLayerType( mLayer ? mLayer->geometryType() : mGeomType );
199  mBackgroundSymbolButton->setLayer( mLayer );
200 
201  // load labeling settings from layer
202  updateGeometryTypeBasedWidgets();
203 
204  mFieldExpressionWidget->setLayer( mLayer );
205  QgsDistanceArea da;
206  if ( mLayer )
207  da.setSourceCrs( mLayer->crs(), QgsProject::instance()->transformContext() );
208  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
209  mFieldExpressionWidget->setGeomCalculator( da );
210 
211  mFieldExpressionWidget->setEnabled( mMode == Labels || !mLayer );
212  mLabelingFrame->setEnabled( mMode == Labels || !mLayer );
213 
214  blockInitSignals( true );
215 
216  mGeometryGenerator->setText( mSettings.geometryGenerator );
217  mGeometryGeneratorGroupBox->setChecked( mSettings.geometryGeneratorEnabled );
218  mGeometryGeneratorType->setCurrentIndex( mGeometryGeneratorType->findData( mSettings.geometryGeneratorType ) );
219 
220  updateWidgetForFormat( mSettings.format() );
221 
222  mFieldExpressionWidget->setRow( -1 );
223  mFieldExpressionWidget->setField( mSettings.fieldName );
224  mCheckBoxSubstituteText->setChecked( mSettings.useSubstitutions );
225  mSubstitutions = mSettings.substitutions;
226 
227  // populate placement options
228  mCentroidRadioWhole->setChecked( mSettings.centroidWhole );
229  mCentroidInsideCheckBox->setChecked( mSettings.centroidInside );
230  mFitInsidePolygonCheckBox->setChecked( mSettings.fitInPolygonOnly );
231  mLineDistanceSpnBx->setValue( mSettings.dist );
232  mLineDistanceUnitWidget->setUnit( mSettings.distUnits );
233  mLineDistanceUnitWidget->setMapUnitScale( mSettings.distMapUnitScale );
234  mOffsetTypeComboBox->setCurrentIndex( mOffsetTypeComboBox->findData( mSettings.offsetType ) );
235  mQuadrantBtnGrp->button( static_cast<int>( mSettings.quadOffset ) )->setChecked( true );
236  mPointOffsetXSpinBox->setValue( mSettings.xOffset );
237  mPointOffsetYSpinBox->setValue( mSettings.yOffset );
238  mPointOffsetUnitWidget->setUnit( mSettings.offsetUnits );
239  mPointOffsetUnitWidget->setMapUnitScale( mSettings.labelOffsetMapUnitScale );
240  mPointAngleSpinBox->setValue( mSettings.angleOffset );
241  chkLineAbove->setChecked( mSettings.placementFlags & QgsPalLayerSettings::AboveLine );
242  chkLineBelow->setChecked( mSettings.placementFlags & QgsPalLayerSettings::BelowLine );
243  chkLineOn->setChecked( mSettings.placementFlags & QgsPalLayerSettings::OnLine );
244  chkLineOrientationDependent->setChecked( !( mSettings.placementFlags & QgsPalLayerSettings::MapOrientation ) );
245 
246  switch ( mSettings.placement )
247  {
249  radAroundPoint->setChecked( true );
250  radAroundCentroid->setChecked( true );
251  //spinAngle->setValue( lyr.angle ); // TODO: uncomment when supported
252  break;
254  radOverPoint->setChecked( true );
255  radOverCentroid->setChecked( true );
256  break;
258  radPredefinedOrder->setChecked( true );
259  break;
261  radLineParallel->setChecked( true );
262  radPolygonPerimeter->setChecked( true );
263  break;
265  radLineCurved->setChecked( true );
266  break;
268  radPolygonHorizontal->setChecked( true );
269  radLineHorizontal->setChecked( true );
270  break;
272  radPolygonFree->setChecked( true );
273  break;
275  radPolygonPerimeterCurved->setChecked( true );
276  break;
277  }
278 
279  // Label repeat distance
280  mRepeatDistanceSpinBox->setValue( mSettings.repeatDistance );
281  mRepeatDistanceUnitWidget->setUnit( mSettings.repeatDistanceUnit );
282  mRepeatDistanceUnitWidget->setMapUnitScale( mSettings.repeatDistanceMapUnitScale );
283 
284  mOverrunDistanceSpinBox->setValue( mSettings.overrunDistance );
285  mOverrunDistanceUnitWidget->setUnit( mSettings.overrunDistanceUnit );
286  mOverrunDistanceUnitWidget->setMapUnitScale( mSettings.overrunDistanceMapUnitScale );
287 
288  mPrioritySlider->setValue( mSettings.priority );
289  mChkNoObstacle->setChecked( mSettings.obstacle );
290  mObstacleFactorSlider->setValue( mSettings.obstacleFactor * 50 );
291  mObstacleTypeComboBox->setCurrentIndex( mObstacleTypeComboBox->findData( mSettings.obstacleType ) );
292  mPolygonObstacleTypeFrame->setEnabled( mSettings.obstacle );
293  mObstaclePriorityFrame->setEnabled( mSettings.obstacle );
294  chkLabelPerFeaturePart->setChecked( mSettings.labelPerPart );
295  mPalShowAllLabelsForLayerChkBx->setChecked( mSettings.displayAll );
296  chkMergeLines->setChecked( mSettings.mergeLines );
297  mMinSizeSpinBox->setValue( mSettings.minFeatureSize );
298  mLimitLabelChkBox->setChecked( mSettings.limitNumLabels );
299  mLimitLabelSpinBox->setValue( mSettings.maxNumLabels );
300 
301  // direction symbol(s)
302  mDirectSymbChkBx->setChecked( mSettings.addDirectionSymbol );
303  mDirectSymbLeftLineEdit->setText( mSettings.leftDirectionSymbol );
304  mDirectSymbRightLineEdit->setText( mSettings.rightDirectionSymbol );
305  mDirectSymbRevChkBx->setChecked( mSettings.reverseDirectionSymbol );
306 
307  mDirectSymbBtnGrp->button( static_cast<int>( mSettings.placeDirectionSymbol ) )->setChecked( true );
308  mUpsidedownBtnGrp->button( static_cast<int>( mSettings.upsidedownLabels ) )->setChecked( true );
309 
310  // curved label max character angles
311  mMaxCharAngleInDSpinBox->setValue( mSettings.maxCurvedCharAngleIn );
312  // lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
313  mMaxCharAngleOutDSpinBox->setValue( std::fabs( mSettings.maxCurvedCharAngleOut ) );
314 
315  wrapCharacterEdit->setText( mSettings.wrapChar );
316  mAutoWrapLengthSpinBox->setValue( mSettings.autoWrapLength );
317  mAutoWrapTypeComboBox->setCurrentIndex( mSettings.useMaxLineLengthForAutoWrap ? 0 : 1 );
318 
319  if ( ( int ) mSettings.multilineAlign < mFontMultiLineAlignComboBox->count() )
320  {
321  mFontMultiLineAlignComboBox->setCurrentIndex( mSettings.multilineAlign );
322  }
323  else
324  {
325  // the default pal layer settings for multiline alignment is to follow label placement, which isn't always available
326  // revert to left alignment in such case
327  mFontMultiLineAlignComboBox->setCurrentIndex( 0 );
328  }
329 
330  chkPreserveRotation->setChecked( mSettings.preserveRotation );
331 
332  mScaleBasedVisibilityChkBx->setChecked( mSettings.scaleVisibility );
333  mMinScaleWidget->setScale( mSettings.minimumScale );
334  mMaxScaleWidget->setScale( mSettings.maximumScale );
335 
336  mFormatNumChkBx->setChecked( mSettings.formatNumbers );
337  mFormatNumDecimalsSpnBx->setValue( mSettings.decimals );
338  mFormatNumPlusSignChkBx->setChecked( mSettings.plusSign );
339 
340  // set pixel size limiting checked state before unit choice so limiting can be
341  // turned on as a default for map units, if minimum trigger value of 0 is used
342  mFontLimitPixelChkBox->setChecked( mSettings.fontLimitPixelSize );
343  mMinPixelLimit = mSettings.fontMinPixelSize; // ignored after first settings save
344  mFontMinPixelSpinBox->setValue( mSettings.fontMinPixelSize == 0 ? 3 : mSettings.fontMinPixelSize );
345  mFontMaxPixelSpinBox->setValue( mSettings.fontMaxPixelSize );
346 
347  mZIndexSpinBox->setValue( mSettings.zIndex );
348 
349  mDataDefinedProperties = mSettings.dataDefinedProperties();
350 
351  // callout settings, to move to custom widget when multiple styles exist
352  if ( mSettings.callout() )
353  {
354  whileBlocking( mCalloutsDrawCheckBox )->setChecked( mSettings.callout()->enabled() );
355  whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( mSettings.callout()->type() ) );
356  updateCalloutWidget( mSettings.callout() );
357  }
358  else
359  {
360  std::unique_ptr< QgsCallout > defaultCallout( QgsApplication::calloutRegistry()->defaultCallout() );
361  whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( defaultCallout->type() ) );
362  whileBlocking( mCalloutsDrawCheckBox )->setChecked( false );
363  updateCalloutWidget( defaultCallout.get() );
364  }
365 
366  updatePlacementWidgets();
367  updateLinePlacementOptions();
368 
369  // needs to come before data defined setup, so connections work
370  blockInitSignals( false );
371 
372  // set up data defined toolbuttons
373  // do this after other widgets are configured, so they can be enabled/disabled
374  populateDataDefinedButtons();
375 
376  enableDataDefinedAlignment( mCoordXDDBtn->isActive() && mCoordYDDBtn->isActive() );
377  updateUi(); // should come after data defined button setup
378 }
379 
380 void QgsLabelingGui::setSettings( const QgsPalLayerSettings &settings )
381 {
382  mSettings = settings;
383  setLayer( mLayer );
384 }
385 
386 void QgsLabelingGui::blockInitSignals( bool block )
387 {
388  chkLineAbove->blockSignals( block );
389  chkLineBelow->blockSignals( block );
390  mPlacePointBtnGrp->blockSignals( block );
391  mPlaceLineBtnGrp->blockSignals( block );
392  mPlacePolygonBtnGrp->blockSignals( block );
393 }
394 
395 void QgsLabelingGui::setLabelMode( LabelMode mode )
396 {
397  mMode = mode;
398  mFieldExpressionWidget->setEnabled( mMode == Labels );
399  mLabelingFrame->setEnabled( mMode == Labels );
400 }
401 
402 QgsPalLayerSettings QgsLabelingGui::layerSettings()
403 {
405 
406  lyr.drawLabels = ( mMode == Labels ) || !mLayer;
407 
408  bool isExpression;
409  lyr.fieldName = mFieldExpressionWidget->currentField( &isExpression );
410  lyr.isExpression = isExpression;
411 
412  lyr.dist = 0;
413  lyr.placementFlags = 0;
414 
415  QWidget *curPlacementWdgt = stackedPlacement->currentWidget();
416  lyr.centroidWhole = mCentroidRadioWhole->isChecked();
417  lyr.centroidInside = mCentroidInsideCheckBox->isChecked();
418  lyr.fitInPolygonOnly = mFitInsidePolygonCheckBox->isChecked();
419  lyr.dist = mLineDistanceSpnBx->value();
420  lyr.distUnits = mLineDistanceUnitWidget->unit();
421  lyr.distMapUnitScale = mLineDistanceUnitWidget->getMapUnitScale();
422  lyr.offsetType = static_cast< QgsPalLayerSettings::OffsetType >( mOffsetTypeComboBox->currentData().toInt() );
423  if ( mQuadrantBtnGrp )
424  {
425  lyr.quadOffset = ( QgsPalLayerSettings::QuadrantPosition )mQuadrantBtnGrp->checkedId();
426  }
427  lyr.xOffset = mPointOffsetXSpinBox->value();
428  lyr.yOffset = mPointOffsetYSpinBox->value();
429  lyr.offsetUnits = mPointOffsetUnitWidget->unit();
430  lyr.labelOffsetMapUnitScale = mPointOffsetUnitWidget->getMapUnitScale();
431  lyr.angleOffset = mPointAngleSpinBox->value();
432  if ( chkLineAbove->isChecked() )
434  if ( chkLineBelow->isChecked() )
436  if ( chkLineOn->isChecked() )
438  if ( ! chkLineOrientationDependent->isChecked() )
440  if ( ( curPlacementWdgt == pagePoint && radAroundPoint->isChecked() )
441  || ( curPlacementWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
442  {
444  }
445  else if ( ( curPlacementWdgt == pagePoint && radOverPoint->isChecked() )
446  || ( curPlacementWdgt == pagePolygon && radOverCentroid->isChecked() ) )
447  {
449  }
450  else if ( curPlacementWdgt == pagePoint && radPredefinedOrder->isChecked() )
451  {
453  }
454  else if ( ( curPlacementWdgt == pageLine && radLineParallel->isChecked() )
455  || ( curPlacementWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) )
456  {
458  }
459  else if ( curPlacementWdgt == pageLine && radLineCurved->isChecked() )
460  {
462  }
463  else if ( curPlacementWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() )
464  {
466  }
467  else if ( ( curPlacementWdgt == pageLine && radLineHorizontal->isChecked() )
468  || ( curPlacementWdgt == pagePolygon && radPolygonHorizontal->isChecked() ) )
469  {
471  }
472  else if ( radPolygonFree->isChecked() )
473  {
475  }
476  else
477  {
478  qFatal( "Invalid settings" );
479  }
480 
481  lyr.repeatDistance = mRepeatDistanceSpinBox->value();
482  lyr.repeatDistanceUnit = mRepeatDistanceUnitWidget->unit();
483  lyr.repeatDistanceMapUnitScale = mRepeatDistanceUnitWidget->getMapUnitScale();
484 
485  lyr.overrunDistance = mOverrunDistanceSpinBox->value();
486  lyr.overrunDistanceUnit = mOverrunDistanceUnitWidget->unit();
487  lyr.overrunDistanceMapUnitScale = mOverrunDistanceUnitWidget->getMapUnitScale();
488 
489  lyr.priority = mPrioritySlider->value();
490  lyr.obstacle = mChkNoObstacle->isChecked() || mMode == ObstaclesOnly;
491  lyr.obstacleFactor = mObstacleFactorSlider->value() / 50.0;
492  lyr.obstacleType = ( QgsPalLayerSettings::ObstacleType )mObstacleTypeComboBox->currentData().toInt();
493  lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
494  lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
495  lyr.mergeLines = chkMergeLines->isChecked();
496 
497  lyr.scaleVisibility = mScaleBasedVisibilityChkBx->isChecked();
498  lyr.minimumScale = mMinScaleWidget->scale();
499  lyr.maximumScale = mMaxScaleWidget->scale();
500  lyr.useSubstitutions = mCheckBoxSubstituteText->isChecked();
501  lyr.substitutions = mSubstitutions;
502 
503  lyr.setFormat( format( false ) );
504 
505  // format numbers
506  lyr.formatNumbers = mFormatNumChkBx->isChecked();
507  lyr.decimals = mFormatNumDecimalsSpnBx->value();
508  lyr.plusSign = mFormatNumPlusSignChkBx->isChecked();
509 
510  // direction symbol(s)
511  lyr.addDirectionSymbol = mDirectSymbChkBx->isChecked();
512  lyr.leftDirectionSymbol = mDirectSymbLeftLineEdit->text();
513  lyr.rightDirectionSymbol = mDirectSymbRightLineEdit->text();
514  lyr.reverseDirectionSymbol = mDirectSymbRevChkBx->isChecked();
515  if ( mDirectSymbBtnGrp )
516  {
517  lyr.placeDirectionSymbol = ( QgsPalLayerSettings::DirectionSymbols )mDirectSymbBtnGrp->checkedId();
518  }
519  if ( mUpsidedownBtnGrp )
520  {
521  lyr.upsidedownLabels = ( QgsPalLayerSettings::UpsideDownLabels )mUpsidedownBtnGrp->checkedId();
522  }
523 
524  lyr.maxCurvedCharAngleIn = mMaxCharAngleInDSpinBox->value();
525  // lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
526  lyr.maxCurvedCharAngleOut = -mMaxCharAngleOutDSpinBox->value();
527 
528 
529  lyr.minFeatureSize = mMinSizeSpinBox->value();
530  lyr.limitNumLabels = mLimitLabelChkBox->isChecked();
531  lyr.maxNumLabels = mLimitLabelSpinBox->value();
532  lyr.fontLimitPixelSize = mFontLimitPixelChkBox->isChecked();
533  lyr.fontMinPixelSize = mFontMinPixelSpinBox->value();
534  lyr.fontMaxPixelSize = mFontMaxPixelSpinBox->value();
535  lyr.wrapChar = wrapCharacterEdit->text();
536  lyr.autoWrapLength = mAutoWrapLengthSpinBox->value();
537  lyr.useMaxLineLengthForAutoWrap = mAutoWrapTypeComboBox->currentIndex() == 0;
538  lyr.multilineAlign = ( QgsPalLayerSettings::MultiLineAlign ) mFontMultiLineAlignComboBox->currentIndex();
539  lyr.preserveRotation = chkPreserveRotation->isChecked();
540  lyr.geometryGenerator = mGeometryGenerator->text();
541  lyr.geometryGeneratorType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
542  lyr.geometryGeneratorEnabled = mGeometryGeneratorGroupBox->isChecked();
543 
544  lyr.layerType = mLayer ? mLayer->geometryType() : mGeomType;
545 
546  lyr.zIndex = mZIndexSpinBox->value();
547 
548  lyr.setDataDefinedProperties( mDataDefinedProperties );
549 
550  // callout settings
551  const QString calloutType = mCalloutStyleComboBox->currentData().toString();
552  std::unique_ptr< QgsCallout > callout;
553  if ( QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
554  {
555  callout.reset( pew->callout()->clone() );
556  }
557  if ( !callout )
558  callout.reset( QgsApplication::calloutRegistry()->createCallout( calloutType ) );
559 
560  callout->setEnabled( mCalloutsDrawCheckBox->isChecked() );
561  lyr.setCallout( callout.release() );
562 
563  return lyr;
564 }
565 
566 
567 void QgsLabelingGui::syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f )
568 {
569  if ( ddBtn->isActive() && !chkBx->isChecked() )
570  {
571  chkBx->setChecked( true );
572  }
573  f->setEnabled( chkBx->isChecked() );
574 }
575 
576 void QgsLabelingGui::updateUi()
577 {
578  // enable/disable inline groupbox-like setups (that need to honor data defined setting)
579 
580  syncDefinedCheckboxFrame( mBufferDrawDDBtn, mBufferDrawChkBx, mBufferFrame );
581  syncDefinedCheckboxFrame( mShapeDrawDDBtn, mShapeDrawChkBx, mShapeFrame );
582  syncDefinedCheckboxFrame( mShadowDrawDDBtn, mShadowDrawChkBx, mShadowFrame );
583 
584  syncDefinedCheckboxFrame( mDirectSymbDDBtn, mDirectSymbChkBx, mDirectSymbFrame );
585  syncDefinedCheckboxFrame( mFormatNumDDBtn, mFormatNumChkBx, mFormatNumFrame );
586  syncDefinedCheckboxFrame( mScaleBasedVisibilityDDBtn, mScaleBasedVisibilityChkBx, mScaleBasedVisibilityFrame );
587  syncDefinedCheckboxFrame( mFontLimitPixelDDBtn, mFontLimitPixelChkBox, mFontLimitPixelFrame );
588 
589  chkMergeLines->setEnabled( !mDirectSymbChkBx->isChecked() );
590  if ( mDirectSymbChkBx->isChecked() )
591  {
592  chkMergeLines->setToolTip( tr( "This option is not compatible with line direction symbols." ) );
593  }
594  else
595  {
596  chkMergeLines->setToolTip( QString() );
597  }
598 }
599 
600 void QgsLabelingGui::setFormatFromStyle( const QString &name, QgsStyle::StyleEntity type )
601 {
602  switch ( type )
603  {
606  case QgsStyle::TagEntity:
609  {
611  return;
612  }
613 
615  {
616  if ( !QgsStyle::defaultStyle()->labelSettingsNames().contains( name ) )
617  return;
618 
620  if ( settings.fieldName.isEmpty() )
621  {
622  // if saved settings doesn't have a field name stored, retain the current one
623  bool isExpression;
624  settings.fieldName = mFieldExpressionWidget->currentField( &isExpression );
625  settings.isExpression = isExpression;
626  }
627  setSettings( settings );
628  break;
629  }
630  }
631 }
632 
633 void QgsLabelingGui::setContext( const QgsSymbolWidgetContext &context )
634 {
635  if ( QgsCalloutWidget *cw = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
636  {
637  cw->setContext( context );
638  }
640 }
641 
642 void QgsLabelingGui::saveFormat()
643 {
644  QgsStyle *style = QgsStyle::defaultStyle();
645  if ( !style )
646  return;
647 
648  QgsStyleSaveDialog saveDlg( this, QgsStyle::LabelSettingsEntity );
649  saveDlg.setDefaultTags( mTextFormatsListWidget->currentTagFilter() );
650  if ( !saveDlg.exec() )
651  return;
652 
653  if ( saveDlg.name().isEmpty() )
654  return;
655 
656  switch ( saveDlg.selectedType() )
657  {
659  {
660  // check if there is no format with same name
661  if ( style->textFormatNames().contains( saveDlg.name() ) )
662  {
663  int res = QMessageBox::warning( this, tr( "Save Text Format" ),
664  tr( "Format with name '%1' already exists. Overwrite?" )
665  .arg( saveDlg.name() ),
666  QMessageBox::Yes | QMessageBox::No );
667  if ( res != QMessageBox::Yes )
668  {
669  return;
670  }
671  style->removeTextFormat( saveDlg.name() );
672  }
673  QStringList symbolTags = saveDlg.tags().split( ',' );
674 
675  QgsTextFormat newFormat = format();
676  style->addTextFormat( saveDlg.name(), newFormat );
677  style->saveTextFormat( saveDlg.name(), newFormat, saveDlg.isFavorite(), symbolTags );
678  break;
679  }
680 
682  {
683  // check if there is no settings with same name
684  if ( style->labelSettingsNames().contains( saveDlg.name() ) )
685  {
686  int res = QMessageBox::warning( this, tr( "Save Label Settings" ),
687  tr( "Label settings with the name '%1' already exist. Overwrite?" )
688  .arg( saveDlg.name() ),
689  QMessageBox::Yes | QMessageBox::No );
690  if ( res != QMessageBox::Yes )
691  {
692  return;
693  }
694  style->removeLabelSettings( saveDlg.name() );
695  }
696  QStringList symbolTags = saveDlg.tags().split( ',' );
697 
698  QgsPalLayerSettings newSettings = layerSettings();
699  style->addLabelSettings( saveDlg.name(), newSettings );
700  style->saveLabelSettings( saveDlg.name(), newSettings, saveDlg.isFavorite(), symbolTags );
701  break;
702  }
703 
706  case QgsStyle::TagEntity:
708  break;
709  }
710 }
711 
712 void QgsLabelingGui::updateGeometryTypeBasedWidgets()
713 {
714  QgsWkbTypes::GeometryType geometryType = mGeomType;
715 
716  if ( mGeometryGeneratorGroupBox->isChecked() )
717  geometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
718  else if ( mLayer )
719  geometryType = mLayer->geometryType();
720 
721  // show/hide options based upon geometry type
722  chkMergeLines->setVisible( geometryType == QgsWkbTypes::LineGeometry );
723  mDirectSymbolsFrame->setVisible( geometryType == QgsWkbTypes::LineGeometry );
724  mMinSizeFrame->setVisible( geometryType != QgsWkbTypes::PointGeometry );
725  mPolygonObstacleTypeFrame->setVisible( geometryType == QgsWkbTypes::PolygonGeometry );
726  mPolygonFeatureOptionsFrame->setVisible( geometryType == QgsWkbTypes::PolygonGeometry );
727 
728 
729  // set placement methods page based on geometry type
730  switch ( geometryType )
731  {
733  stackedPlacement->setCurrentWidget( pagePoint );
734  break;
736  stackedPlacement->setCurrentWidget( pageLine );
737  break;
739  stackedPlacement->setCurrentWidget( pagePolygon );
740  break;
742  break;
744  qFatal( "unknown geometry type unexpected" );
745  }
746 
747  if ( geometryType == QgsWkbTypes::PointGeometry )
748  {
749  // follow placement alignment is only valid for point layers
750  if ( mFontMultiLineAlignComboBox->findText( tr( "Follow label placement" ) ) == -1 )
751  mFontMultiLineAlignComboBox->addItem( tr( "Follow label placement" ) );
752  }
753  else
754  {
755  int idx = mFontMultiLineAlignComboBox->findText( tr( "Follow label placement" ) );
756  if ( idx >= 0 )
757  mFontMultiLineAlignComboBox->removeItem( idx );
758  }
759 
760  updatePlacementWidgets();
761  updateLinePlacementOptions();
762 }
763 
764 void QgsLabelingGui::showGeometryGeneratorExpressionBuilder()
765 {
766  QgsExpressionBuilderDialog expressionBuilder( mLayer );
767 
768  expressionBuilder.setExpressionText( mGeometryGenerator->text() );
769  expressionBuilder.setExpressionContext( createExpressionContext() );
770 
771  if ( expressionBuilder.exec() )
772  {
773  mGeometryGenerator->setText( expressionBuilder.expressionText() );
774  }
775 }
776 
777 void QgsLabelingGui::validateGeometryGeneratorExpression()
778 {
779  bool valid = true;
780 
781  if ( mGeometryGeneratorGroupBox->isChecked() )
782  {
783  if ( !mPreviewFeature.isValid() && mLayer )
784  mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
785 
786  QgsExpression expression( mGeometryGenerator->text() );
787  QgsExpressionContext context = createExpressionContext();
788  context.setFeature( mPreviewFeature );
789 
790  expression.prepare( &context );
791 
792  if ( expression.hasParserError() )
793  {
794  mGeometryGeneratorWarningLabel->setText( expression.parserErrorString() );
795  valid = false;
796  }
797  else
798  {
799  const QVariant result = expression.evaluate( &context );
800  const QgsGeometry geometry = result.value<QgsGeometry>();
801  QgsWkbTypes::GeometryType configuredGeometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
802  if ( geometry.isNull() )
803  {
804  mGeometryGeneratorWarningLabel->setText( tr( "Result of the expression is not a geometry" ) );
805  valid = false;
806  }
807  else if ( geometry.type() != configuredGeometryType )
808  {
809  mGeometryGeneratorWarningLabel->setText( QStringLiteral( "<p>%1</p><p><a href=\"#determineGeometryGeneratorType\">%2</a></p>" ).arg(
810  tr( "Result of the expression does not match configured geometry type." ),
811  tr( "Change to %1" ).arg( QgsWkbTypes::geometryDisplayString( geometry.type() ) ) ) );
812  valid = false;
813  }
814  }
815  }
816 
817  // The collapsible groupbox internally changes the visibility of this
818  // Work around by setting the visibility deferred in the next event loop cycle.
819  QTimer *timer = new QTimer();
820  connect( timer, &QTimer::timeout, this, [this, valid]()
821  {
822  mGeometryGeneratorWarningLabel->setVisible( !valid );
823  } );
824  connect( timer, &QTimer::timeout, timer, &QTimer::deleteLater );
825  timer->start( 0 );
826 }
827 
828 void QgsLabelingGui::determineGeometryGeneratorType()
829 {
830  if ( !mPreviewFeature.isValid() && mLayer )
831  mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
832 
833  QgsExpression expression( mGeometryGenerator->text() );
834  QgsExpressionContext context = createExpressionContext();
835  context.setFeature( mPreviewFeature );
836 
837  expression.prepare( &context );
838  const QgsGeometry geometry = expression.evaluate( &context ).value<QgsGeometry>();
839 
840  mGeometryGeneratorType->setCurrentIndex( mGeometryGeneratorType->findData( geometry.type() ) );
841 }
842 
843 void QgsLabelingGui::calloutTypeChanged()
844 {
845  QString newCalloutType = mCalloutStyleComboBox->currentData().toString();
846  QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() );
847  if ( pew )
848  {
849  if ( pew->callout() && pew->callout()->type() == newCalloutType )
850  return;
851  }
852 
853  // get creation function for new callout from registry
855  QgsCalloutAbstractMetadata *am = registry->calloutMetadata( newCalloutType );
856  if ( !am ) // check whether the metadata is assigned
857  return;
858 
859  // change callout to a new one (with different type)
860  // base new callout on existing callout's properties
861  std::unique_ptr< QgsCallout > newCallout( am->createCallout( pew && pew->callout() ? pew->callout()->properties( QgsReadWriteContext() ) : QVariantMap(), QgsReadWriteContext() ) );
862  if ( !newCallout )
863  return;
864 
865  updateCalloutWidget( newCallout.get() );
866  updatePreview();
867 }
868 
869 
870 //
871 // QgsLabelSettingsDialog
872 //
873 
874 QgsLabelSettingsDialog::QgsLabelSettingsDialog( const QgsPalLayerSettings &settings, QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, QWidget *parent,
875  QgsWkbTypes::GeometryType geomType )
876  : QDialog( parent )
877 {
878  QVBoxLayout *vLayout = new QVBoxLayout();
879  mWidget = new QgsLabelingGui( layer, mapCanvas, settings, nullptr, geomType );
880  vLayout->addWidget( mWidget );
881  mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok, Qt::Horizontal );
882  connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
883  connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
884  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsLabelSettingsDialog::showHelp );
885  vLayout->addWidget( mButtonBox );
886  setLayout( vLayout );
887  setWindowTitle( tr( "Label Settings" ) );
888 }
889 
890 QDialogButtonBox *QgsLabelSettingsDialog::buttonBox() const
891 {
892  return mButtonBox;
893 }
894 
895 void QgsLabelSettingsDialog::showHelp()
896 {
897  QgsHelp::openHelp( QStringLiteral( "style_library/label_settings.html" ) );
898 }
899 
900 
901 
static const QString EXPR_ORIGINAL_VALUE
Inbuilt variable name for value original value variable.
Class for parsing and evaluation of expressions (formerly called "search strings").
virtual QgsCallout * callout()=0
Returns the callout defined by the current settings in the widget.
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
double xOffset
Horizontal offset of label.
The class is used as a container of context for various read/write operations on other objects...
QString geometryGenerator
The geometry generator expression. Null if disabled.
Base class for all map layer types.
Definition: qgsmaplayer.h:79
double maxCurvedCharAngleOut
Maximum angle between outside curved label characters (valid range -20.0 to -95.0) ...
double maximumScale
The maximum map scale (i.e.
Abstract base class for callout renderers.
Definition: qgscallout.h:46
QString leftDirectionSymbol
String to use for left direction arrows.
static QgsCalloutRegistry * calloutRegistry()
Returns the application&#39;s callout registry, used for managing callout types.
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:260
QgsUnitTypes::RenderUnit repeatDistanceUnit
Units for repeating labels for a single feature.
QStringList calloutTypes() const
Returns a list of all available callout types.
QgsMapUnitScale overrunDistanceMapUnitScale
Map unit scale for label overrun distance.
QgsMapLayerType type() const
Returns the type of the layer.
double angleOffset
Label rotation, in degrees clockwise.
bool formatNumbers
Set to true to format numeric label text as numbers (e.g.
UpsideDownLabels upsidedownLabels
Controls whether upside down labels are displayed and how they are handled.
double obstacleFactor
Obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels, 1.0 less likely to be covered
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point...
Arranges candidates following the curvature of a line feature. Applies to line layers only...
bool addLabelSettings(const QString &name, const QgsPalLayerSettings &settings, bool update=false)
Adds label settings with the specified name to the style.
Definition: qgsstyle.cpp:281
int decimals
Number of decimal places to show for numeric labels.
bool obstacle
true if features for layer are obstacles to labels of other layers.
double repeatDistance
Distance for repeating labels for a single feature.
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
QuadrantPosition quadOffset
Sets the quadrant in which to offset labels from feature.
QgsUnitTypes::RenderUnit offsetUnits
Units for offsets of label.
double yOffset
Vertical offset of label.
Stores metadata about one callout renderer class.
bool isActive() const
Returns true if the button has an active property.
bool addDirectionSymbol
If true, &#39;<&#39; or &#39;>&#39; (or custom strings set via leftDirectionSymbol and rightDirectionSymbol) will be ...
bool geometryGeneratorEnabled
Defines if the geometry generator is enabled or not. If disabled, the standard geometry will be taken...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
bool drawLabels
Whether to draw labels for this layer.
bool mergeLines
true if connected line features with identical label text should be merged prior to generating label ...
QgsMapUnitScale repeatDistanceMapUnitScale
Map unit scale for repeating labels for a single feature.
MultiLineAlign multilineAlign
Horizontal alignment of multi-line labels.
Base class for widgets which allow control over the properties of callouts.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
A widget for customizing text formatting settings.
QgsCalloutAbstractMetadata * calloutMetadata(const QString &type) const
Returns the metadata for specified the specified callout type.
int autoWrapLength
If non-zero, indicates that label text should be automatically wrapped to (ideally) the specified num...
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
double maxCurvedCharAngleIn
Maximum angle between inside curved label characters (valid range 20.0 to 60.0).
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:75
bool reverseDirectionSymbol
True if direction symbols should be reversed.
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:74
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...
QgsStringReplacementCollection substitutions
Substitution collection for automatic text substitution with labels.
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
StyleEntity
Enum for Entities involved in a style.
Definition: qgsstyle.h:177
ObstacleType obstacleType
Controls how features act as obstacles for labels.
QStringList textFormatNames() const
Returns a list of names of text formats in the style.
Definition: qgsstyle.cpp:2038
QgsPalLayerSettings labelSettings(const QString &name) const
Returns the label settings with the specified name.
Definition: qgsstyle.cpp:2048
Labels can be placed directly over a line feature.
bool displayAll
If true, all features will be labelled even when overlaps occur.
A button for controlling property overrides which may apply to a widget.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the label&#39;s property collection, used for data defined overrides.
void changed()
Should be emitted whenever configuration changes happened on this symbol layer configuration.
int fontMaxPixelSize
Maximum pixel size for showing rendered map unit labels (1 - 10000).
Contains settings which reflect the context in which a symbol (or renderer) widget is shown...
QStringList labelSettingsNames() const
Returns a list of names of label settings in the style.
Definition: qgsstyle.cpp:2066
Labels can be placed above a line feature.
static QString geometryDisplayString(GeometryType type)
Returns a display string for a geometry type.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
static const QString EXPR_SYMBOL_COLOR
Inbuilt variable name for symbol color variable.
OffsetType
Behavior modifier for label offset and distance, only applies in some label placement modes...
Single scope for storing variables and functions for use within a QgsExpressionContext.
int maxNumLabels
The maximum number of labels which should be drawn for this layer.
virtual void setFormatFromStyle(const QString &name, QgsStyle::StyleEntity type)
Sets the current text settings from a style entry.
virtual QString type() const =0
Returns a unique string representing the callout type.
bool plusSign
Whether &#39;+&#39; signs should be prepended to positive numeric labels.
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:96
unsigned int placementFlags
QgsWkbTypes::GeometryType geometryGeneratorType
The type of the result geometry of the geometry generator.
QString wrapChar
Wrapping character string.
QgsCalloutWidget *(* QgsCalloutWidgetFunc)(QgsVectorLayer *)
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
bool saveTextFormat(const QString &name, const QgsTextFormat &format, bool favorite, const QStringList &tags)
Adds a text format to the database.
Definition: qgsstyle.cpp:712
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
QString rightDirectionSymbol
String to use for right direction arrows.
bool preserveRotation
True if label rotation should be preserved during label pin/unpin operations.
bool removeTextFormat(const QString &name)
Removes a text format from the style.
Definition: qgsstyle.cpp:745
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon&#39;...
bool centroidWhole
true if feature centroid should be calculated from the whole feature, or false if only the visible pa...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:227
bool scaleVisibility
Set to true to limit label visibility to a range of scales.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
QgsMapUnitScale distMapUnitScale
Map unit scale for label feature distance.
bool fitInPolygonOnly
true if only labels which completely fit within a polygon are allowed.
OffsetType offsetType
Offset type for layer (only applies in certain placement modes)
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:442
double dist
Distance from feature to the label.
bool useSubstitutions
True if substitutions should be applied.
void setWidgetFunction(QgsCalloutWidgetFunc f)
Convenience metadata class that uses static functions to create callouts and their widgets...
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
Registry of available callout classes.
Labels can be placed below a line feature.
bool limitNumLabels
true if the number of labels drawn should be limited.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user...
Signifies that the AboveLine and BelowLine flags should respect the map&#39;s orientation rather than the...
bool isExpression
true if this label is made from a expression string, e.g., FieldName || &#39;mm&#39;
double overrunDistance
Distance which labels are allowed to overrun past the start or end of line features.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:126
QgsUnitTypes::RenderUnit overrunDistanceUnit
Units for label overrun distance.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
void setCallout(QgsCallout *callout)
Sets the label callout renderer, responsible for drawing label callouts.
Container for all settings relating to text rendering.
bool saveLabelSettings(const QString &name, const QgsPalLayerSettings &settings, bool favorite, const QStringList &tags)
Adds label settings to the database.
Definition: qgsstyle.cpp:800
bool centroidInside
true if centroid positioned labels must be placed inside their corresponding feature polygon...
virtual QVariantMap properties(const QgsReadWriteContext &context) const
Returns the properties describing the callout encoded in a string format.
Definition: qgscallout.cpp:50
Represents a vector layer which manages a vector based data sets.
Arranges candidates following the curvature of a polygon&#39;s boundary. Applies to polygon layers only...
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
double minFeatureSize
Minimum feature size (in millimeters) for a feature to be labelled.
bool removeLabelSettings(const QString &name)
Removes label settings from the style.
Definition: qgsstyle.cpp:833
int fontMinPixelSize
Minimum pixel size for showing rendered map unit labels (1 - 1000).
int priority
Label priority.
A generic dialog for building expression strings.
bool labelPerPart
true if every part of a multi-part feature should be labeled.
QgsUnitTypes::RenderUnit distUnits
Units the distance from feature to the label.
bool useMaxLineLengthForAutoWrap
If true, indicates that when auto wrapping label text the autoWrapLength length indicates the maximum...
virtual QgsCallout * createCallout(const QVariantMap &properties, const QgsReadWriteContext &context)=0
Create a callout of this type given the map of properties.
QgsMapUnitScale labelOffsetMapUnitScale
Map unit scale for label offset.
void setEnabled(bool enabled)
Sets whether the callout is enabled.
Definition: qgscallout.cpp:136
double minimumScale
The minimum map scale (i.e.
QString fieldName
Name of field (or an expression) to use for label text.
bool fontLimitPixelSize
true if label sizes should be limited by pixel size.
ObstacleType
Valid obstacle types, which affect how features within the layer will act as obstacles for labels...
DirectionSymbols placeDirectionSymbol
Placement option for direction symbols.
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
QgsWkbTypes::GeometryType layerType
Geometry type of layers associated with these settings.