QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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"
35 #include <mutex>
36 
37 #include <QButtonGroup>
38 #include <QMessageBox>
39 
41 
42 QgsExpressionContext QgsLabelingGui::createExpressionContext() const
43 {
44  QgsExpressionContext expContext;
48  if ( mCanvas )
49  expContext << QgsExpressionContextUtils::mapSettingsScope( mCanvas->mapSettings() );
50 
51  if ( mLayer )
52  expContext << QgsExpressionContextUtils::layerScope( mLayer );
53 
55 
56  //TODO - show actual value
57  expContext.setOriginalValueVariable( QVariant() );
59 
60  return expContext;
61 }
62 
63 static bool _initCalloutWidgetFunction( const QString &name, QgsCalloutWidgetFunc f )
64 {
66 
67  QgsCalloutAbstractMetadata *abstractMetadata = registry->calloutMetadata( name );
68  if ( !abstractMetadata )
69  {
70  QgsDebugMsg( QStringLiteral( "Failed to find callout entry in registry: %1" ).arg( name ) );
71  return false;
72  }
73  QgsCalloutMetadata *metadata = dynamic_cast<QgsCalloutMetadata *>( abstractMetadata );
74  if ( !metadata )
75  {
76  QgsDebugMsg( QStringLiteral( "Failed to cast callout's metadata: " ) .arg( name ) );
77  return false;
78  }
79  metadata->setWidgetFunction( f );
80  return true;
81 }
82 
83 void QgsLabelingGui::initCalloutWidgets()
84 {
85  _initCalloutWidgetFunction( QStringLiteral( "simple" ), QgsSimpleLineCalloutWidget::create );
86  _initCalloutWidgetFunction( QStringLiteral( "manhattan" ), QgsManhattanLineCalloutWidget::create );
87 }
88 
89 void QgsLabelingGui::updateCalloutWidget( QgsCallout *callout )
90 {
91  if ( !callout )
92  {
93  mCalloutStackedWidget->setCurrentWidget( pageDummy );
94  return;
95  }
96 
97  if ( mCalloutStackedWidget->currentWidget() != pageDummy )
98  {
99  // stop updating from the original widget
100  if ( QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
101  disconnect( pew, &QgsCalloutWidget::changed, this, &QgsLabelingGui::updatePreview );
102  }
103 
105  if ( QgsCalloutAbstractMetadata *am = registry->calloutMetadata( callout->type() ) )
106  {
107  if ( QgsCalloutWidget *w = am->createCalloutWidget( mLayer ) )
108  {
109 
110  QgsWkbTypes::GeometryType geometryType = mGeomType;
111  if ( mGeometryGeneratorGroupBox->isChecked() )
112  geometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
113  else if ( mLayer )
114  geometryType = mLayer->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 
130 void QgsLabelingGui::showObstacleSettings()
131 {
132  QgsExpressionContext context = createExpressionContext();
133 
134  QgsSymbolWidgetContext symbolContext;
135  symbolContext.setExpressionContext( &context );
136  symbolContext.setMapCanvas( mMapCanvas );
137 
138  QgsLabelObstacleSettingsWidget *widget = new QgsLabelObstacleSettingsWidget( nullptr, mLayer );
139  widget->setDataDefinedProperties( mDataDefinedProperties );
140  widget->setSettings( mObstacleSettings );
141  widget->setGeometryType( mLayer ? mLayer->geometryType() : QgsWkbTypes::UnknownGeometry );
142  widget->setContext( symbolContext );
143 
144  auto applySettings = [ = ]
145  {
146  mObstacleSettings = widget->settings();
147  const QgsPropertyCollection obstacleDataDefinedProperties = widget->dataDefinedProperties();
148  widget->updateDataDefinedProperties( mDataDefinedProperties );
149  emit widgetChanged();
150  };
151 
153  if ( panel && panel->dockMode() )
154  {
155  connect( widget, &QgsLabelSettingsWidgetBase::changed, this, [ = ]
156  {
157  applySettings();
158  } );
159  panel->openPanel( widget );
160  }
161  else
162  {
163  QgsLabelSettingsWidgetDialog dialog( widget, this );
164 
165  dialog.buttonBox()->addButton( QDialogButtonBox::Help );
166  connect( dialog.buttonBox(), &QDialogButtonBox::helpRequested, this, [ = ]
167  {
168  QgsHelp::openHelp( QStringLiteral( "style_library/label_settings.html#obstacles" ) );
169  } );
170 
171  if ( dialog.exec() )
172  {
173  applySettings();
174  }
175  // reactivate button's window
176  activateWindow();
177  }
178 }
179 
180 void QgsLabelingGui::showLineAnchorSettings()
181 {
182  QgsExpressionContext context = createExpressionContext();
183 
184  QgsSymbolWidgetContext symbolContext;
185  symbolContext.setExpressionContext( &context );
186  symbolContext.setMapCanvas( mMapCanvas );
187 
188  QgsLabelLineAnchorWidget *widget = new QgsLabelLineAnchorWidget( nullptr, mLayer );
189  widget->setDataDefinedProperties( mDataDefinedProperties );
190  widget->setSettings( mLineSettings );
191  widget->setGeometryType( mLayer ? mLayer->geometryType() : QgsWkbTypes::UnknownGeometry );
192  widget->setContext( symbolContext );
193 
194  auto applySettings = [ = ]
195  {
196  const QgsLabelLineSettings widgetSettings = widget->settings();
197  mLineSettings.setLineAnchorPercent( widgetSettings.lineAnchorPercent() );
198  mLineSettings.setAnchorType( widgetSettings.anchorType() );
199  const QgsPropertyCollection obstacleDataDefinedProperties = widget->dataDefinedProperties();
200  widget->updateDataDefinedProperties( mDataDefinedProperties );
201  emit widgetChanged();
202  };
203 
205  if ( panel && panel->dockMode() )
206  {
207  connect( widget, &QgsLabelSettingsWidgetBase::changed, this, [ = ]
208  {
209  applySettings();
210  } );
211  panel->openPanel( widget );
212  }
213  else
214  {
215  QgsLabelSettingsWidgetDialog dialog( widget, this );
216  if ( dialog.exec() )
217  {
218  applySettings();
219  }
220  // reactivate button's window
221  activateWindow();
222  }
223 }
224 
225 QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsPalLayerSettings &layerSettings, QWidget *parent, QgsWkbTypes::GeometryType geomType )
226  : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, layer )
227  , mSettings( layerSettings )
228  , mMode( NoLabels )
229  , mCanvas( mapCanvas )
230 {
231  mGeomType = geomType;
232  static std::once_flag initialized;
233  std::call_once( initialized, [ = ]( )
234  {
235  initCalloutWidgets();
236  } );
237 
238  mFontMultiLineAlignComboBox->addItem( tr( "Left" ), QgsPalLayerSettings::MultiLeft );
239  mFontMultiLineAlignComboBox->addItem( tr( "Center" ), QgsPalLayerSettings::MultiCenter );
240  mFontMultiLineAlignComboBox->addItem( tr( "Right" ), QgsPalLayerSettings::MultiRight );
241  mFontMultiLineAlignComboBox->addItem( tr( "Justify" ), QgsPalLayerSettings::MultiJustify );
242 
243  // connections for groupboxes with separate activation checkboxes (that need to honor data defined setting)
244  connect( mBufferDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
245  connect( mEnableMaskChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
246  connect( mShapeDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
247  connect( mCalloutsDrawCheckBox, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
248  connect( mShadowDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
249  connect( mDirectSymbChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
250  connect( mFormatNumChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
251  connect( mScaleBasedVisibilityChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
252  connect( mFontLimitPixelChkBox, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
253  connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
254  connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
255  connect( mGeometryGeneratorExpressionButton, &QToolButton::clicked, this, &QgsLabelingGui::showGeometryGeneratorExpressionBuilder );
256  connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
257  connect( mGeometryGenerator, &QgsCodeEditorExpression::textChanged, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
258  connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::validateGeometryGeneratorExpression );
259  connect( mObstacleSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingGui::showObstacleSettings );
260  connect( mLineAnchorSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingGui::showLineAnchorSettings );
261 
262  mFieldExpressionWidget->registerExpressionContextGenerator( this );
263 
264  mMinScaleWidget->setMapCanvas( mCanvas );
265  mMinScaleWidget->setShowCurrentScaleButton( true );
266  mMaxScaleWidget->setMapCanvas( mCanvas );
267  mMaxScaleWidget->setShowCurrentScaleButton( true );
268 
269  const QStringList calloutTypes = QgsApplication::calloutRegistry()->calloutTypes();
270  for ( const QString &type : calloutTypes )
271  {
272  mCalloutStyleComboBox->addItem( QgsApplication::calloutRegistry()->calloutMetadata( type )->icon(),
273  QgsApplication::calloutRegistry()->calloutMetadata( type )->visibleName(), type );
274  }
275 
276  mGeometryGeneratorWarningLabel->setStyleSheet( QStringLiteral( "color: #FFC107;" ) );
277  mGeometryGeneratorWarningLabel->setTextInteractionFlags( Qt::TextBrowserInteraction );
278  connect( mGeometryGeneratorWarningLabel, &QLabel::linkActivated, this, [this]( const QString & link )
279  {
280  if ( link == QLatin1String( "#determineGeometryGeneratorType" ) )
281  determineGeometryGeneratorType();
282  } );
283 
284  connect( mCalloutStyleComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::calloutTypeChanged );
285 
286  mLblNoObstacle1->installEventFilter( this );
287 
288  setLayer( layer );
289 }
290 
291 void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
292 {
293  mPreviewFeature = QgsFeature();
294 
295  if ( ( !mapLayer || mapLayer->type() != QgsMapLayerType::VectorLayer ) && mGeomType == QgsWkbTypes::UnknownGeometry )
296  {
297  setEnabled( false );
298  return;
299  }
300 
301  setEnabled( true );
302 
303  QgsVectorLayer *layer = static_cast<QgsVectorLayer *>( mapLayer );
304  mLayer = layer;
305 
306  mTextFormatsListWidget->setLayerType( mLayer ? mLayer->geometryType() : mGeomType );
307  mBackgroundSymbolButton->setLayer( mLayer );
308 
309  // load labeling settings from layer
310  updateGeometryTypeBasedWidgets();
311 
312  mFieldExpressionWidget->setLayer( mLayer );
313  QgsDistanceArea da;
314  if ( mLayer )
315  da.setSourceCrs( mLayer->crs(), QgsProject::instance()->transformContext() );
316  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
317  mFieldExpressionWidget->setGeomCalculator( da );
318 
319  mFieldExpressionWidget->setEnabled( mMode == Labels || !mLayer );
320  mLabelingFrame->setEnabled( mMode == Labels || !mLayer );
321 
322  blockInitSignals( true );
323 
324  mGeometryGenerator->setText( mSettings.geometryGenerator );
325  mGeometryGeneratorGroupBox->setChecked( mSettings.geometryGeneratorEnabled );
326  if ( !mSettings.geometryGeneratorEnabled )
327  mGeometryGeneratorGroupBox->setCollapsed( true );
328  mGeometryGeneratorType->setCurrentIndex( mGeometryGeneratorType->findData( mSettings.geometryGeneratorType ) );
329 
330  updateWidgetForFormat( mSettings.format() );
331 
332  mFieldExpressionWidget->setRow( -1 );
333  mFieldExpressionWidget->setField( mSettings.fieldName );
334  mCheckBoxSubstituteText->setChecked( mSettings.useSubstitutions );
335  mSubstitutions = mSettings.substitutions;
336 
337  // populate placement options
338  mCentroidRadioWhole->setChecked( mSettings.centroidWhole );
339  mCentroidInsideCheckBox->setChecked( mSettings.centroidInside );
340  mFitInsidePolygonCheckBox->setChecked( mSettings.fitInPolygonOnly );
341  mLineDistanceSpnBx->setValue( mSettings.dist );
342  mLineDistanceUnitWidget->setUnit( mSettings.distUnits );
343  mLineDistanceUnitWidget->setMapUnitScale( mSettings.distMapUnitScale );
344  mOffsetTypeComboBox->setCurrentIndex( mOffsetTypeComboBox->findData( mSettings.offsetType ) );
345  mQuadrantBtnGrp->button( static_cast<int>( mSettings.quadOffset ) )->setChecked( true );
346  mPointOffsetXSpinBox->setValue( mSettings.xOffset );
347  mPointOffsetYSpinBox->setValue( mSettings.yOffset );
348  mPointOffsetUnitWidget->setUnit( mSettings.offsetUnits );
349  mPointOffsetUnitWidget->setMapUnitScale( mSettings.labelOffsetMapUnitScale );
350  mPointAngleSpinBox->setValue( mSettings.angleOffset );
351  chkLineAbove->setChecked( mSettings.lineSettings().placementFlags() & QgsLabeling::LinePlacementFlag::AboveLine );
352  chkLineBelow->setChecked( mSettings.lineSettings().placementFlags() & QgsLabeling::LinePlacementFlag::BelowLine );
353  chkLineOn->setChecked( mSettings.lineSettings().placementFlags() & QgsLabeling::LinePlacementFlag::OnLine );
354  chkLineOrientationDependent->setChecked( !( mSettings.lineSettings().placementFlags() & QgsLabeling::LinePlacementFlag::MapOrientation ) );
355 
356  mCheckAllowLabelsOutsidePolygons->setChecked( mSettings.polygonPlacementFlags() & QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon );
357 
358  const int placementIndex = mPlacementModeComboBox->findData( mSettings.placement );
359  if ( placementIndex >= 0 )
360  {
361  mPlacementModeComboBox->setCurrentIndex( placementIndex );
362  }
363  else
364  {
365  // use default placement for layer type
366  mPlacementModeComboBox->setCurrentIndex( 0 );
367  }
368 
369  // Label repeat distance
370  mRepeatDistanceSpinBox->setValue( mSettings.repeatDistance );
371  mRepeatDistanceUnitWidget->setUnit( mSettings.repeatDistanceUnit );
372  mRepeatDistanceUnitWidget->setMapUnitScale( mSettings.repeatDistanceMapUnitScale );
373 
374  mOverrunDistanceSpinBox->setValue( mSettings.lineSettings().overrunDistance() );
375  mOverrunDistanceUnitWidget->setUnit( mSettings.lineSettings().overrunDistanceUnit() );
376  mOverrunDistanceUnitWidget->setMapUnitScale( mSettings.lineSettings().overrunDistanceMapUnitScale() );
377 
378  mPrioritySlider->setValue( mSettings.priority );
379  mChkNoObstacle->setChecked( mSettings.obstacleSettings().isObstacle() );
380 
381  mObstacleSettings = mSettings.obstacleSettings();
382  mLineSettings = mSettings.lineSettings();
383 
384  chkLabelPerFeaturePart->setChecked( mSettings.labelPerPart );
385  mPalShowAllLabelsForLayerChkBx->setChecked( mSettings.displayAll );
386  chkMergeLines->setChecked( mSettings.lineSettings().mergeLines() );
387  mMinSizeSpinBox->setValue( mSettings.thinningSettings().minimumFeatureSize() );
388  mLimitLabelChkBox->setChecked( mSettings.thinningSettings().limitNumberOfLabelsEnabled() );
389  mLimitLabelSpinBox->setValue( mSettings.thinningSettings().maximumNumberLabels() );
390 
391  // direction symbol(s)
392  mDirectSymbChkBx->setChecked( mSettings.lineSettings().addDirectionSymbol() );
393  mDirectSymbLeftLineEdit->setText( mSettings.lineSettings().leftDirectionSymbol() );
394  mDirectSymbRightLineEdit->setText( mSettings.lineSettings().rightDirectionSymbol() );
395  mDirectSymbRevChkBx->setChecked( mSettings.lineSettings().reverseDirectionSymbol() );
396 
397  mDirectSymbBtnGrp->button( static_cast<int>( mSettings.lineSettings().directionSymbolPlacement() ) )->setChecked( true );
398  mUpsidedownBtnGrp->button( static_cast<int>( mSettings.upsidedownLabels ) )->setChecked( true );
399 
400  // curved label max character angles
401  mMaxCharAngleInDSpinBox->setValue( mSettings.maxCurvedCharAngleIn );
402  // lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
403  mMaxCharAngleOutDSpinBox->setValue( std::fabs( mSettings.maxCurvedCharAngleOut ) );
404 
405  wrapCharacterEdit->setText( mSettings.wrapChar );
406  mAutoWrapLengthSpinBox->setValue( mSettings.autoWrapLength );
407  mAutoWrapTypeComboBox->setCurrentIndex( mSettings.useMaxLineLengthForAutoWrap ? 0 : 1 );
408 
409  if ( mFontMultiLineAlignComboBox->findData( mSettings.multilineAlign ) != -1 )
410  {
411  mFontMultiLineAlignComboBox->setCurrentIndex( mFontMultiLineAlignComboBox->findData( mSettings.multilineAlign ) );
412  }
413  else
414  {
415  // the default pal layer settings for multiline alignment is to follow label placement, which isn't always available
416  // revert to left alignment in such case
417  mFontMultiLineAlignComboBox->setCurrentIndex( 0 );
418  }
419 
420  chkPreserveRotation->setChecked( mSettings.preserveRotation );
421 
422  mScaleBasedVisibilityChkBx->setChecked( mSettings.scaleVisibility );
423  mMinScaleWidget->setScale( mSettings.minimumScale );
424  mMaxScaleWidget->setScale( mSettings.maximumScale );
425 
426  mFormatNumChkBx->setChecked( mSettings.formatNumbers );
427  mFormatNumDecimalsSpnBx->setValue( mSettings.decimals );
428  mFormatNumPlusSignChkBx->setChecked( mSettings.plusSign );
429 
430  // set pixel size limiting checked state before unit choice so limiting can be
431  // turned on as a default for map units, if minimum trigger value of 0 is used
432  mFontLimitPixelChkBox->setChecked( mSettings.fontLimitPixelSize );
433  mMinPixelLimit = mSettings.fontMinPixelSize; // ignored after first settings save
434  mFontMinPixelSpinBox->setValue( mSettings.fontMinPixelSize == 0 ? 3 : mSettings.fontMinPixelSize );
435  mFontMaxPixelSpinBox->setValue( mSettings.fontMaxPixelSize );
436 
437  mZIndexSpinBox->setValue( mSettings.zIndex );
438 
439  mDataDefinedProperties = mSettings.dataDefinedProperties();
440 
441  // callout settings, to move to custom widget when multiple styles exist
442  if ( auto *lCallout = mSettings.callout() )
443  {
444  whileBlocking( mCalloutsDrawCheckBox )->setChecked( lCallout->enabled() );
445  whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( lCallout->type() ) );
446  updateCalloutWidget( lCallout );
447  }
448  else
449  {
450  std::unique_ptr< QgsCallout > defaultCallout( QgsApplication::calloutRegistry()->defaultCallout() );
451  whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( defaultCallout->type() ) );
452  whileBlocking( mCalloutsDrawCheckBox )->setChecked( false );
453  updateCalloutWidget( defaultCallout.get() );
454  }
455 
456  updatePlacementWidgets();
457  updateLinePlacementOptions();
458 
459  // needs to come before data defined setup, so connections work
460  blockInitSignals( false );
461 
462  // set up data defined toolbuttons
463  // do this after other widgets are configured, so they can be enabled/disabled
464  populateDataDefinedButtons();
465 
466  enableDataDefinedAlignment( mCoordXDDBtn->isActive() && mCoordYDDBtn->isActive() );
467  updateUi(); // should come after data defined button setup
468 }
469 
470 void QgsLabelingGui::setSettings( const QgsPalLayerSettings &settings )
471 {
472  mSettings = settings;
473  setLayer( mLayer );
474 }
475 
476 void QgsLabelingGui::blockInitSignals( bool block )
477 {
478  chkLineAbove->blockSignals( block );
479  chkLineBelow->blockSignals( block );
480  mPlacementModeComboBox->blockSignals( block );
481 }
482 
483 void QgsLabelingGui::setLabelMode( LabelMode mode )
484 {
485  mMode = mode;
486  mFieldExpressionWidget->setEnabled( mMode == Labels );
487  mLabelingFrame->setEnabled( mMode == Labels );
488 }
489 
490 QgsPalLayerSettings QgsLabelingGui::layerSettings()
491 {
493 
494  lyr.drawLabels = ( mMode == Labels ) || !mLayer;
495 
496  bool isExpression;
497  lyr.fieldName = mFieldExpressionWidget->currentField( &isExpression );
498  lyr.isExpression = isExpression;
499 
500  lyr.dist = 0;
501 
502  QgsLabeling::PolygonPlacementFlags polygonPlacementFlags = QgsLabeling::PolygonPlacementFlag::AllowPlacementInsideOfPolygon;
503  if ( mCheckAllowLabelsOutsidePolygons->isChecked() )
504  polygonPlacementFlags |= QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
505  lyr.setPolygonPlacementFlags( polygonPlacementFlags );
506 
507  lyr.centroidWhole = mCentroidRadioWhole->isChecked();
508  lyr.centroidInside = mCentroidInsideCheckBox->isChecked();
509  lyr.fitInPolygonOnly = mFitInsidePolygonCheckBox->isChecked();
510  lyr.dist = mLineDistanceSpnBx->value();
511  lyr.distUnits = mLineDistanceUnitWidget->unit();
512  lyr.distMapUnitScale = mLineDistanceUnitWidget->getMapUnitScale();
513  lyr.offsetType = static_cast< QgsPalLayerSettings::OffsetType >( mOffsetTypeComboBox->currentData().toInt() );
514  if ( mQuadrantBtnGrp )
515  {
516  lyr.quadOffset = ( QgsPalLayerSettings::QuadrantPosition )mQuadrantBtnGrp->checkedId();
517  }
518  lyr.xOffset = mPointOffsetXSpinBox->value();
519  lyr.yOffset = mPointOffsetYSpinBox->value();
520  lyr.offsetUnits = mPointOffsetUnitWidget->unit();
521  lyr.labelOffsetMapUnitScale = mPointOffsetUnitWidget->getMapUnitScale();
522  lyr.angleOffset = mPointAngleSpinBox->value();
523 
524  QgsLabeling::LinePlacementFlags linePlacementFlags = QgsLabeling::LinePlacementFlags();
525  if ( chkLineAbove->isChecked() )
526  linePlacementFlags |= QgsLabeling::LinePlacementFlag::AboveLine;
527  if ( chkLineBelow->isChecked() )
528  linePlacementFlags |= QgsLabeling::LinePlacementFlag::BelowLine;
529  if ( chkLineOn->isChecked() )
530  linePlacementFlags |= QgsLabeling::LinePlacementFlag::OnLine;
531  if ( ! chkLineOrientationDependent->isChecked() )
532  linePlacementFlags |= QgsLabeling::LinePlacementFlag::MapOrientation;
533  lyr.lineSettings().setPlacementFlags( linePlacementFlags );
534 
535  lyr.placement = static_cast< QgsPalLayerSettings::Placement >( mPlacementModeComboBox->currentData().toInt() );
536 
537  lyr.repeatDistance = mRepeatDistanceSpinBox->value();
538  lyr.repeatDistanceUnit = mRepeatDistanceUnitWidget->unit();
539  lyr.repeatDistanceMapUnitScale = mRepeatDistanceUnitWidget->getMapUnitScale();
540 
541  lyr.lineSettings().setOverrunDistance( mOverrunDistanceSpinBox->value() );
542  lyr.lineSettings().setOverrunDistanceUnit( mOverrunDistanceUnitWidget->unit() );
543  lyr.lineSettings().setOverrunDistanceMapUnitScale( mOverrunDistanceUnitWidget->getMapUnitScale() );
544 
545  lyr.priority = mPrioritySlider->value();
546 
547  mObstacleSettings.setIsObstacle( mChkNoObstacle->isChecked() || mMode == ObstaclesOnly );
548  lyr.setObstacleSettings( mObstacleSettings );
549 
550  lyr.lineSettings().setLineAnchorPercent( mLineSettings.lineAnchorPercent() );
551  lyr.lineSettings().setAnchorType( mLineSettings.anchorType() );
552 
553  lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
554  lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
555  lyr.lineSettings().setMergeLines( chkMergeLines->isChecked() );
556 
557  lyr.scaleVisibility = mScaleBasedVisibilityChkBx->isChecked();
558  lyr.minimumScale = mMinScaleWidget->scale();
559  lyr.maximumScale = mMaxScaleWidget->scale();
560  lyr.useSubstitutions = mCheckBoxSubstituteText->isChecked();
561  lyr.substitutions = mSubstitutions;
562 
563  lyr.setFormat( format( false ) );
564 
565  // format numbers
566  lyr.formatNumbers = mFormatNumChkBx->isChecked();
567  lyr.decimals = mFormatNumDecimalsSpnBx->value();
568  lyr.plusSign = mFormatNumPlusSignChkBx->isChecked();
569 
570  // direction symbol(s)
571  lyr.lineSettings().setAddDirectionSymbol( mDirectSymbChkBx->isChecked() );
572  lyr.lineSettings().setLeftDirectionSymbol( mDirectSymbLeftLineEdit->text() );
573  lyr.lineSettings().setRightDirectionSymbol( mDirectSymbRightLineEdit->text() );
574  lyr.lineSettings().setReverseDirectionSymbol( mDirectSymbRevChkBx->isChecked() );
575  if ( mDirectSymbBtnGrp )
576  {
577  lyr.lineSettings().setDirectionSymbolPlacement( static_cast< QgsLabelLineSettings::DirectionSymbolPlacement >( mDirectSymbBtnGrp->checkedId() ) );
578  }
579  if ( mUpsidedownBtnGrp )
580  {
581  lyr.upsidedownLabels = ( QgsPalLayerSettings::UpsideDownLabels )mUpsidedownBtnGrp->checkedId();
582  }
583 
584  lyr.maxCurvedCharAngleIn = mMaxCharAngleInDSpinBox->value();
585  // lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
586  lyr.maxCurvedCharAngleOut = -mMaxCharAngleOutDSpinBox->value();
587 
588 
589  lyr.thinningSettings().setMinimumFeatureSize( mMinSizeSpinBox->value() );
590  lyr.thinningSettings().setLimitNumberLabelsEnabled( mLimitLabelChkBox->isChecked() );
591  lyr.thinningSettings().setMaximumNumberLabels( mLimitLabelSpinBox->value() );
592  lyr.fontLimitPixelSize = mFontLimitPixelChkBox->isChecked();
593  lyr.fontMinPixelSize = mFontMinPixelSpinBox->value();
594  lyr.fontMaxPixelSize = mFontMaxPixelSpinBox->value();
595  lyr.wrapChar = wrapCharacterEdit->text();
596  lyr.autoWrapLength = mAutoWrapLengthSpinBox->value();
597  lyr.useMaxLineLengthForAutoWrap = mAutoWrapTypeComboBox->currentIndex() == 0;
598  lyr.multilineAlign = static_cast< QgsPalLayerSettings::MultiLineAlign >( mFontMultiLineAlignComboBox->currentData().toInt() );
599  lyr.preserveRotation = chkPreserveRotation->isChecked();
600  lyr.geometryGenerator = mGeometryGenerator->text();
601  lyr.geometryGeneratorType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
602  lyr.geometryGeneratorEnabled = mGeometryGeneratorGroupBox->isChecked();
603 
604  lyr.layerType = mLayer ? mLayer->geometryType() : mGeomType;
605 
606  lyr.zIndex = mZIndexSpinBox->value();
607 
608  lyr.setDataDefinedProperties( mDataDefinedProperties );
609 
610  // callout settings
611  const QString calloutType = mCalloutStyleComboBox->currentData().toString();
612  std::unique_ptr< QgsCallout > callout;
613  if ( QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
614  {
615  callout.reset( pew->callout()->clone() );
616  }
617  if ( !callout )
618  callout.reset( QgsApplication::calloutRegistry()->createCallout( calloutType ) );
619 
620  callout->setEnabled( mCalloutsDrawCheckBox->isChecked() );
621  lyr.setCallout( callout.release() );
622 
623  return lyr;
624 }
625 
626 void QgsLabelingGui::syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f )
627 {
628  if ( ddBtn->isActive() && !chkBx->isChecked() )
629  {
630  chkBx->setChecked( true );
631  }
632  f->setEnabled( chkBx->isChecked() );
633 }
634 
635 bool QgsLabelingGui::eventFilter( QObject *object, QEvent *event )
636 {
637  if ( object == mLblNoObstacle1 )
638  {
639  if ( event->type() == QEvent::MouseButtonPress && dynamic_cast< QMouseEvent * >( event )->button() == Qt::LeftButton )
640  {
641  // clicking the obstacle label toggles the checkbox, just like a "normal" checkbox label...
642  mChkNoObstacle->setChecked( !mChkNoObstacle->isChecked() );
643  return true;
644  }
645  return false;
646  }
647  return QgsTextFormatWidget::eventFilter( object, event );
648 }
649 
650 void QgsLabelingGui::updateUi()
651 {
652  // enable/disable inline groupbox-like setups (that need to honor data defined setting)
653 
654  syncDefinedCheckboxFrame( mBufferDrawDDBtn, mBufferDrawChkBx, mBufferFrame );
655  syncDefinedCheckboxFrame( mEnableMaskDDBtn, mEnableMaskChkBx, mMaskFrame );
656  syncDefinedCheckboxFrame( mShapeDrawDDBtn, mShapeDrawChkBx, mShapeFrame );
657  syncDefinedCheckboxFrame( mShadowDrawDDBtn, mShadowDrawChkBx, mShadowFrame );
658  syncDefinedCheckboxFrame( mCalloutDrawDDBtn, mCalloutsDrawCheckBox, mCalloutFrame );
659 
660  syncDefinedCheckboxFrame( mDirectSymbDDBtn, mDirectSymbChkBx, mDirectSymbFrame );
661  syncDefinedCheckboxFrame( mFormatNumDDBtn, mFormatNumChkBx, mFormatNumFrame );
662  syncDefinedCheckboxFrame( mScaleBasedVisibilityDDBtn, mScaleBasedVisibilityChkBx, mScaleBasedVisibilityFrame );
663  syncDefinedCheckboxFrame( mFontLimitPixelDDBtn, mFontLimitPixelChkBox, mFontLimitPixelFrame );
664 
665  chkMergeLines->setEnabled( !mDirectSymbChkBx->isChecked() );
666  if ( mDirectSymbChkBx->isChecked() )
667  {
668  chkMergeLines->setToolTip( tr( "This option is not compatible with line direction symbols." ) );
669  }
670  else
671  {
672  chkMergeLines->setToolTip( QString() );
673  }
674 }
675 
676 void QgsLabelingGui::setFormatFromStyle( const QString &name, QgsStyle::StyleEntity type )
677 {
678  switch ( type )
679  {
682  case QgsStyle::TagEntity:
687  {
689  return;
690  }
691 
693  {
694  if ( !QgsStyle::defaultStyle()->labelSettingsNames().contains( name ) )
695  return;
696 
698  if ( settings.fieldName.isEmpty() )
699  {
700  // if saved settings doesn't have a field name stored, retain the current one
701  bool isExpression;
702  settings.fieldName = mFieldExpressionWidget->currentField( &isExpression );
703  settings.isExpression = isExpression;
704  }
705  setSettings( settings );
706  break;
707  }
708  }
709 }
710 
711 void QgsLabelingGui::setContext( const QgsSymbolWidgetContext &context )
712 {
713  if ( QgsCalloutWidget *cw = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
714  {
715  cw->setContext( context );
716  }
718 }
719 
720 void QgsLabelingGui::saveFormat()
721 {
722  QgsStyle *style = QgsStyle::defaultStyle();
723  if ( !style )
724  return;
725 
727  saveDlg.setDefaultTags( mTextFormatsListWidget->currentTagFilter() );
728  if ( !saveDlg.exec() )
729  return;
730 
731  if ( saveDlg.name().isEmpty() )
732  return;
733 
734  switch ( saveDlg.selectedType() )
735  {
737  {
738  // check if there is no format with same name
739  if ( style->textFormatNames().contains( saveDlg.name() ) )
740  {
741  int res = QMessageBox::warning( this, tr( "Save Text Format" ),
742  tr( "Format with name '%1' already exists. Overwrite?" )
743  .arg( saveDlg.name() ),
744  QMessageBox::Yes | QMessageBox::No );
745  if ( res != QMessageBox::Yes )
746  {
747  return;
748  }
749  style->removeTextFormat( saveDlg.name() );
750  }
751  QStringList symbolTags = saveDlg.tags().split( ',' );
752 
753  QgsTextFormat newFormat = format();
754  style->addTextFormat( saveDlg.name(), newFormat );
755  style->saveTextFormat( saveDlg.name(), newFormat, saveDlg.isFavorite(), symbolTags );
756  break;
757  }
758 
760  {
761  // check if there is no settings with same name
762  if ( style->labelSettingsNames().contains( saveDlg.name() ) )
763  {
764  int res = QMessageBox::warning( this, tr( "Save Label Settings" ),
765  tr( "Label settings with the name '%1' already exist. Overwrite?" )
766  .arg( saveDlg.name() ),
767  QMessageBox::Yes | QMessageBox::No );
768  if ( res != QMessageBox::Yes )
769  {
770  return;
771  }
772  style->removeLabelSettings( saveDlg.name() );
773  }
774  QStringList symbolTags = saveDlg.tags().split( ',' );
775 
776  QgsPalLayerSettings newSettings = layerSettings();
777  style->addLabelSettings( saveDlg.name(), newSettings );
778  style->saveLabelSettings( saveDlg.name(), newSettings, saveDlg.isFavorite(), symbolTags );
779  break;
780  }
781 
784  case QgsStyle::TagEntity:
788  break;
789  }
790 }
791 
792 void QgsLabelingGui::updateGeometryTypeBasedWidgets()
793 {
794  QgsWkbTypes::GeometryType geometryType = mGeomType;
795 
796  if ( mGeometryGeneratorGroupBox->isChecked() )
797  geometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
798  else if ( mLayer )
799  geometryType = mLayer->geometryType();
800 
801  // show/hide options based upon geometry type
802  chkMergeLines->setVisible( geometryType == QgsWkbTypes::LineGeometry );
803  mDirectSymbolsFrame->setVisible( geometryType == QgsWkbTypes::LineGeometry );
804  mMinSizeFrame->setVisible( geometryType != QgsWkbTypes::PointGeometry );
805  mPolygonFeatureOptionsFrame->setVisible( geometryType == QgsWkbTypes::PolygonGeometry );
806 
807 
808  const QgsPalLayerSettings::Placement prevPlacement = static_cast< QgsPalLayerSettings::Placement >( mPlacementModeComboBox->currentData().toInt() );
809  mPlacementModeComboBox->clear();
810 
811  switch ( geometryType )
812  {
814  mPlacementModeComboBox->addItem( tr( "Cartographic" ), QgsPalLayerSettings::OrderedPositionsAroundPoint );
815  mPlacementModeComboBox->addItem( tr( "Around Point" ), QgsPalLayerSettings::AroundPoint );
816  mPlacementModeComboBox->addItem( tr( "Offset from Point" ), QgsPalLayerSettings::OverPoint );
817  break;
818 
820  mPlacementModeComboBox->addItem( tr( "Parallel" ), QgsPalLayerSettings::Line );
821  mPlacementModeComboBox->addItem( tr( "Curved" ), QgsPalLayerSettings::Curved );
822  mPlacementModeComboBox->addItem( tr( "Horizontal" ), QgsPalLayerSettings::Horizontal );
823  break;
824 
826  mPlacementModeComboBox->addItem( tr( "Offset from Centroid" ), QgsPalLayerSettings::OverPoint );
827  mPlacementModeComboBox->addItem( tr( "Around Centroid" ), QgsPalLayerSettings::AroundPoint );
828  mPlacementModeComboBox->addItem( tr( "Horizontal" ), QgsPalLayerSettings::Horizontal );
829  mPlacementModeComboBox->addItem( tr( "Free (Angled)" ), QgsPalLayerSettings::Free );
830  mPlacementModeComboBox->addItem( tr( "Using Perimeter" ), QgsPalLayerSettings::Line );
831  mPlacementModeComboBox->addItem( tr( "Using Perimeter (Curved)" ), QgsPalLayerSettings::PerimeterCurved );
832  mPlacementModeComboBox->addItem( tr( "Outside Polygons" ), QgsPalLayerSettings::OutsidePolygons );
833  break;
834 
836  break;
838  qFatal( "unknown geometry type unexpected" );
839  }
840 
841  if ( mPlacementModeComboBox->findData( prevPlacement ) != -1 )
842  {
843  mPlacementModeComboBox->setCurrentIndex( mPlacementModeComboBox->findData( prevPlacement ) );
844  }
845 
846  if ( geometryType == QgsWkbTypes::PointGeometry || geometryType == QgsWkbTypes::PolygonGeometry )
847  {
848  // follow placement alignment is only valid for point or polygon layers
849  if ( mFontMultiLineAlignComboBox->findData( QgsPalLayerSettings::MultiFollowPlacement ) == -1 )
850  mFontMultiLineAlignComboBox->addItem( tr( "Follow Label Placement" ), QgsPalLayerSettings::MultiFollowPlacement );
851  }
852  else
853  {
854  int idx = mFontMultiLineAlignComboBox->findData( QgsPalLayerSettings::MultiFollowPlacement );
855  if ( idx >= 0 )
856  mFontMultiLineAlignComboBox->removeItem( idx );
857  }
858 
859  updatePlacementWidgets();
860  updateLinePlacementOptions();
861 }
862 
863 void QgsLabelingGui::showGeometryGeneratorExpressionBuilder()
864 {
865  QgsExpressionBuilderDialog expressionBuilder( mLayer );
866 
867  expressionBuilder.setExpressionText( mGeometryGenerator->text() );
868  expressionBuilder.setExpressionContext( createExpressionContext() );
869 
870  if ( expressionBuilder.exec() )
871  {
872  mGeometryGenerator->setText( expressionBuilder.expressionText() );
873  }
874 }
875 
876 void QgsLabelingGui::validateGeometryGeneratorExpression()
877 {
878  bool valid = true;
879 
880  if ( mGeometryGeneratorGroupBox->isChecked() )
881  {
882  if ( !mPreviewFeature.isValid() && mLayer )
883  mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
884 
885  QgsExpression expression( mGeometryGenerator->text() );
886  QgsExpressionContext context = createExpressionContext();
887  context.setFeature( mPreviewFeature );
888 
889  expression.prepare( &context );
890 
891  if ( expression.hasParserError() )
892  {
893  mGeometryGeneratorWarningLabel->setText( expression.parserErrorString() );
894  valid = false;
895  }
896  else
897  {
898  const QVariant result = expression.evaluate( &context );
899  const QgsGeometry geometry = result.value<QgsGeometry>();
900  QgsWkbTypes::GeometryType configuredGeometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
901  if ( geometry.isNull() )
902  {
903  mGeometryGeneratorWarningLabel->setText( tr( "Result of the expression is not a geometry" ) );
904  valid = false;
905  }
906  else if ( geometry.type() != configuredGeometryType )
907  {
908  mGeometryGeneratorWarningLabel->setText( QStringLiteral( "<p>%1</p><p><a href=\"#determineGeometryGeneratorType\">%2</a></p>" ).arg(
909  tr( "Result of the expression does not match configured geometry type." ),
910  tr( "Change to %1" ).arg( QgsWkbTypes::geometryDisplayString( geometry.type() ) ) ) );
911  valid = false;
912  }
913  }
914  }
915 
916  // The collapsible groupbox internally changes the visibility of this
917  // Work around by setting the visibility deferred in the next event loop cycle.
918  QTimer *timer = new QTimer();
919  connect( timer, &QTimer::timeout, this, [this, valid]()
920  {
921  mGeometryGeneratorWarningLabel->setVisible( !valid );
922  } );
923  connect( timer, &QTimer::timeout, timer, &QTimer::deleteLater );
924  timer->start( 0 );
925 }
926 
927 void QgsLabelingGui::determineGeometryGeneratorType()
928 {
929  if ( !mPreviewFeature.isValid() && mLayer )
930  mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
931 
932  QgsExpression expression( mGeometryGenerator->text() );
933  QgsExpressionContext context = createExpressionContext();
934  context.setFeature( mPreviewFeature );
935 
936  expression.prepare( &context );
937  const QgsGeometry geometry = expression.evaluate( &context ).value<QgsGeometry>();
938 
939  mGeometryGeneratorType->setCurrentIndex( mGeometryGeneratorType->findData( geometry.type() ) );
940 }
941 
942 void QgsLabelingGui::calloutTypeChanged()
943 {
944  QString newCalloutType = mCalloutStyleComboBox->currentData().toString();
945  QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() );
946  if ( pew )
947  {
948  if ( pew->callout() && pew->callout()->type() == newCalloutType )
949  return;
950  }
951 
952  // get creation function for new callout from registry
954  QgsCalloutAbstractMetadata *am = registry->calloutMetadata( newCalloutType );
955  if ( !am ) // check whether the metadata is assigned
956  return;
957 
958  // change callout to a new one (with different type)
959  // base new callout on existing callout's properties
960  std::unique_ptr< QgsCallout > newCallout( am->createCallout( pew && pew->callout() ? pew->callout()->properties( QgsReadWriteContext() ) : QVariantMap(), QgsReadWriteContext() ) );
961  if ( !newCallout )
962  return;
963 
964  updateCalloutWidget( newCallout.get() );
965  updatePreview();
966 }
967 
968 
969 //
970 // QgsLabelSettingsDialog
971 //
972 
973 QgsLabelSettingsDialog::QgsLabelSettingsDialog( const QgsPalLayerSettings &settings, QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, QWidget *parent,
974  QgsWkbTypes::GeometryType geomType )
975  : QDialog( parent )
976 {
977  QVBoxLayout *vLayout = new QVBoxLayout();
978  mWidget = new QgsLabelingGui( layer, mapCanvas, settings, nullptr, geomType );
979  vLayout->addWidget( mWidget );
980  mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok, Qt::Horizontal );
981  connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
982  connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
983  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsLabelSettingsDialog::showHelp );
984  vLayout->addWidget( mButtonBox );
985  setLayout( vLayout );
986  setWindowTitle( tr( "Label Settings" ) );
987 }
988 
989 QDialogButtonBox *QgsLabelSettingsDialog::buttonBox() const
990 {
991  return mButtonBox;
992 }
993 
994 void QgsLabelSettingsDialog::showHelp()
995 {
996  QgsHelp::openHelp( QStringLiteral( "style_library/label_settings.html" ) );
997 }
998 
999 
1000 
static QgsCalloutRegistry * calloutRegistry()
Returns the application's callout registry, used for managing callout types.
Stores metadata about one callout renderer class.
virtual QgsCallout * createCallout(const QVariantMap &properties, const QgsReadWriteContext &context)=0
Create a callout of this type given the map of properties.
Convenience metadata class that uses static functions to create callouts and their widgets.
void setWidgetFunction(QgsCalloutWidgetFunc f)
Registry of available callout classes.
QgsCalloutAbstractMetadata * calloutMetadata(const QString &type) const
Returns the metadata for specified the specified callout type.
QStringList calloutTypes() const
Returns a list of all available callout types.
QgsCallout * createCallout(const QString &type, const QVariantMap &properties=QVariantMap(), const QgsReadWriteContext &context=QgsReadWriteContext()) const
Creates a new instance of a callout, given the callout type and properties.
Base class for widgets which allow control over the properties of callouts.
void changed()
Should be emitted whenever configuration changes happened on this symbol layer configuration.
virtual QgsCallout * callout()=0
Returns the callout defined by the current settings in the widget.
Abstract base class for callout renderers.
Definition: qgscallout.h:47
void setEnabled(bool enabled)
Sets whether the callout is enabled.
Definition: qgscallout.cpp:145
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.
Definition: qgscallout.cpp:57
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
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.
A generic dialog for building expression strings.
Single scope for storing variables and functions for use within a QgsExpressionContext.
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 * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
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.
Class for parsing and evaluation of expressions (formerly called "search strings").
This class wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
A widget for customising label line anchor settings.
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.
Contains settings related to how the label engine places and formats labels for line features (or pol...
void setPlacementFlags(QgsLabeling::LinePlacementFlags 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 setLeftDirectionSymbol(const QString &symbol)
Sets the string to use for left direction arrows.
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 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 setOverrunDistance(double distance)
Sets the distance which labels are allowed to overrun past the start or end of line features.
void setOverrunDistanceUnit(const QgsUnitTypes::RenderUnit &unit)
Sets the unit for label overrun distance.
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...
A widget for customising label obstacle settings.
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 setGeometryType(QgsWkbTypes::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 ...
void setDataDefinedProperties(const QgsPropertyCollection &dataDefinedProperties)
Sets the current data defined properties to show in the widget.
virtual void setGeometryType(QgsWkbTypes::GeometryType type)
Sets the geometry type of the features to customize the widget accordingly.
QgsPropertyCollection dataDefinedProperties() const
Returns the current data defined properties state as specified in the widget.
A blocking dialog containing a QgsLabelSettingsWidgetBase.
void setMaximumNumberLabels(int number)
Sets the maximum number of labels which should be drawn for this layer.
void setLimitNumberLabelsEnabled(bool enabled)
Sets whether the the number of labels drawn for the layer should be limited.
void setMinimumFeatureSize(double size)
Sets the minimum feature size (in millimeters) for a feature to be labelled.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:86
Base class for all map layer types.
Definition: qgsmaplayer.h:85
QgsMapLayerType type
Definition: qgsmaplayer.h:92
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.
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...
bool displayAll
If true, all features will be labelled even when overlaps occur.
QString wrapChar
Wrapping character string.
double xOffset
Horizontal offset of label.
bool drawLabels
Whether to draw labels for this layer.
bool fontLimitPixelSize
true if label sizes should be limited by pixel size.
QuadrantPosition quadOffset
Sets the quadrant in which to offset labels from feature.
double minimumScale
The minimum map scale (i.e.
QgsWkbTypes::GeometryType geometryGeneratorType
The type of the result geometry of the geometry generator.
QgsUnitTypes::RenderUnit offsetUnits
Units for offsets of label.
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...
Placement
Placement modes which determine how label candidates are generated for a feature.
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
@ Free
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
@ OrderedPositionsAroundPoint
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
@ OutsidePolygons
Candidates are placed outside of polygon boundaries. Applies to polygon layers only....
bool centroidInside
true if centroid positioned labels must be placed inside their corresponding feature polygon,...
int priority
Label priority.
bool labelPerPart
true if every part of a multi-part feature should be labeled.
@ MultiJustify
Justified.
QgsUnitTypes::RenderUnit distUnits
Units the distance from feature to the label.
QgsUnitTypes::RenderUnit repeatDistanceUnit
Units for repeating labels for a single feature.
OffsetType offsetType
Offset type for layer (only applies in certain placement modes)
MultiLineAlign multilineAlign
Horizontal alignment of multi-line labels.
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)
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
void setPolygonPlacementFlags(QgsLabeling::PolygonPlacementFlags flags)
Sets the polygon placement flags, which dictate how polygon labels can be placed.
OffsetType
Behavior modifier for label offset and distance, only applies in some label placement modes.
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.
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.
QgsMapUnitScale repeatDistanceMapUnitScale
Map unit scale for repeating labels for a single feature.
bool centroidWhole
true if feature centroid should be calculated from the whole feature, or false if only the visible pa...
UpsideDownLabels 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.
QgsWkbTypes::GeometryType layerType
Geometry type of layers associated with these settings.
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...
const QgsLabelThinningSettings & thinningSettings() const
Returns the label thinning settings.
bool useSubstitutions
True if substitutions should be applied.
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
bool dockMode()
Returns the dock mode state.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:501
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:105
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
A button for controlling property overrides which may apply to a widget.
bool isActive() const
Returns true if the button has an active property.
The class is used as a container of context for various read/write operations on other objects.
a dialog for setting properties of a newly saved style.
bool removeLabelSettings(const QString &name)
Removes label settings from the style.
Definition: qgsstyle.cpp:1058
bool saveLabelSettings(const QString &name, const QgsPalLayerSettings &settings, bool favorite, const QStringList &tags)
Adds label settings to the database.
Definition: qgsstyle.cpp:1024
QStringList textFormatNames() const
Returns a list of names of text formats in the style.
Definition: qgsstyle.cpp:2112
bool removeTextFormat(const QString &name)
Removes a text format from the style.
Definition: qgsstyle.cpp:984
StyleEntity
Enum for Entities involved in a style.
Definition: qgsstyle.h:179
@ LabelSettingsEntity
Label settings.
Definition: qgsstyle.h:185
@ TextFormatEntity
Text formats.
Definition: qgsstyle.h:184
@ SmartgroupEntity
Smart groups.
Definition: qgsstyle.h:183
@ Symbol3DEntity
3D symbol entity (since QGIS 3.14)
Definition: qgsstyle.h:187
@ SymbolEntity
Symbols.
Definition: qgsstyle.h:180
@ TagEntity
Tags.
Definition: qgsstyle.h:181
@ ColorrampEntity
Color ramps.
Definition: qgsstyle.h:182
@ LegendPatchShapeEntity
Legend patch shape (since QGIS 3.14)
Definition: qgsstyle.h:186
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:128
QStringList labelSettingsNames() const
Returns a list of names of label settings in the style.
Definition: qgsstyle.cpp:2176
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:316
QgsPalLayerSettings labelSettings(const QString &name) const
Returns the label settings with the specified name.
Definition: qgsstyle.cpp:2122
bool saveTextFormat(const QString &name, const QgsTextFormat &format, bool favorite, const QStringList &tags)
Adds a text format to the database.
Definition: qgsstyle.cpp:950
bool addLabelSettings(const QString &name, const QgsPalLayerSettings &settings, bool update=false)
Adds label settings with the specified name to the style.
Definition: qgsstyle.cpp:337
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 setFormatFromStyle(const QString &name, QgsStyle::StyleEntity type)
Sets the current text settings from a style entry.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
Container for all settings relating to text rendering.
Definition: qgstextformat.h:41
Represents a vector layer which manages a vector based data sets.
static QString geometryDisplayString(GeometryType type) SIP_HOLDGIL
Returns a display string for a geometry type.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:263
QgsCalloutWidget *(* QgsCalloutWidgetFunc)(QgsVectorLayer *)
#define QgsDebugMsg(str)
Definition: qgslogger.h:38