QGIS API Documentation  3.12.1-București (121cc00ff0)
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"
34 #include <mutex>
35 
36 #include <QButtonGroup>
37 #include <QMessageBox>
38 
40 
41 QgsExpressionContext QgsLabelingGui::createExpressionContext() const
42 {
43  QgsExpressionContext expContext;
47  if ( mCanvas )
48  expContext << QgsExpressionContextUtils::mapSettingsScope( mCanvas->mapSettings() );
49 
50  if ( mLayer )
51  expContext << QgsExpressionContextUtils::layerScope( mLayer );
52 
54 
55  //TODO - show actual value
56  expContext.setOriginalValueVariable( QVariant() );
58 
59  return expContext;
60 }
61 
62 static bool _initCalloutWidgetFunction( const QString &name, QgsCalloutWidgetFunc f )
63 {
65 
66  QgsCalloutAbstractMetadata *abstractMetadata = registry->calloutMetadata( name );
67  if ( !abstractMetadata )
68  {
69  QgsDebugMsg( QStringLiteral( "Failed to find callout entry in registry: %1" ).arg( name ) );
70  return false;
71  }
72  QgsCalloutMetadata *metadata = dynamic_cast<QgsCalloutMetadata *>( abstractMetadata );
73  if ( !metadata )
74  {
75  QgsDebugMsg( QStringLiteral( "Failed to cast callout's metadata: " ) .arg( name ) );
76  return false;
77  }
78  metadata->setWidgetFunction( f );
79  return true;
80 }
81 
82 void QgsLabelingGui::initCalloutWidgets()
83 {
84  _initCalloutWidgetFunction( QStringLiteral( "simple" ), QgsSimpleLineCalloutWidget::create );
85  _initCalloutWidgetFunction( QStringLiteral( "manhattan" ), QgsManhattanLineCalloutWidget::create );
86 }
87 
88 void QgsLabelingGui::updateCalloutWidget( QgsCallout *callout )
89 {
90  if ( !callout )
91  {
92  mCalloutStackedWidget->setCurrentWidget( pageDummy );
93  return;
94  }
95 
96  if ( mCalloutStackedWidget->currentWidget() != pageDummy )
97  {
98  // stop updating from the original widget
99  if ( QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
100  disconnect( pew, &QgsCalloutWidget::changed, this, &QgsLabelingGui::updatePreview );
101  }
102 
104  if ( QgsCalloutAbstractMetadata *am = registry->calloutMetadata( callout->type() ) )
105  {
106  if ( QgsCalloutWidget *w = am->createCalloutWidget( mLayer ) )
107  {
108 
109  QgsWkbTypes::GeometryType geometryType = mGeomType;
110  if ( mGeometryGeneratorGroupBox->isChecked() )
111  geometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
112  else if ( mLayer )
113  geometryType = mLayer->geometryType();
114  w->setGeometryType( geometryType );
115  w->setCallout( callout );
116 
117  w->setContext( context() );
118  mCalloutStackedWidget->addWidget( w );
119  mCalloutStackedWidget->setCurrentWidget( w );
120  // start receiving updates from widget
121  connect( w, &QgsCalloutWidget::changed, this, &QgsLabelingGui::updatePreview );
122  return;
123  }
124  }
125  // When anything is not right
126  mCalloutStackedWidget->setCurrentWidget( pageDummy );
127 }
128 
129 void QgsLabelingGui::showObstacleSettings()
130 {
131  QgsExpressionContext context = createExpressionContext();
132 
133  QgsSymbolWidgetContext symbolContext;
134  symbolContext.setExpressionContext( &context );
135  symbolContext.setMapCanvas( mMapCanvas );
136 
137  QgsLabelObstacleSettingsWidget *widget = new QgsLabelObstacleSettingsWidget( nullptr, mLayer );
138  widget->setDataDefinedProperties( mDataDefinedProperties );
139  widget->setSettings( mObstacleSettings );
140  widget->setGeometryType( mLayer ? mLayer->geometryType() : QgsWkbTypes::UnknownGeometry );
141  widget->setContext( symbolContext );
142 
143  auto applySettings = [ = ]
144  {
145  mObstacleSettings = widget->settings();
146  const QgsPropertyCollection obstacleDataDefinedProperties = widget->dataDefinedProperties();
147  widget->updateDataDefinedProperties( mDataDefinedProperties );
148  emit widgetChanged();
149  };
150 
152  if ( panel && panel->dockMode() )
153  {
154  connect( widget, &QgsLabelSettingsWidgetBase::changed, this, [ = ]
155  {
156  applySettings();
157  } );
158  panel->openPanel( widget );
159  }
160  else
161  {
162  QgsLabelSettingsWidgetDialog dialog( widget, this );
163  if ( dialog.exec() )
164  {
165  applySettings();
166  }
167  // reactivate button's window
168  activateWindow();
169  }
170 }
171 
172 QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsPalLayerSettings &layerSettings, QWidget *parent, QgsWkbTypes::GeometryType geomType )
173  : QgsTextFormatWidget( mapCanvas, parent, QgsTextFormatWidget::Labeling, layer )
174  , mGeomType( geomType )
175  , mSettings( layerSettings )
176  , mMode( NoLabels )
177  , mCanvas( mapCanvas )
178 {
179  static std::once_flag initialized;
180  std::call_once( initialized, [ = ]( )
181  {
182  initCalloutWidgets();
183  } );
184 
185  // connections for groupboxes with separate activation checkboxes (that need to honor data defined setting)
186  connect( mBufferDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
187  connect( mEnableMaskChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
188  connect( mShapeDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
189  connect( mShadowDrawChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
190  connect( mDirectSymbChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
191  connect( mFormatNumChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
192  connect( mScaleBasedVisibilityChkBx, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
193  connect( mFontLimitPixelChkBox, &QAbstractButton::toggled, this, &QgsLabelingGui::updateUi );
194  connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
195  connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
196  connect( mGeometryGeneratorExpressionButton, &QToolButton::clicked, this, &QgsLabelingGui::showGeometryGeneratorExpressionBuilder );
197  connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
198  connect( mGeometryGenerator, &QgsCodeEditorExpression::textChanged, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
199  connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::validateGeometryGeneratorExpression );
200  connect( mObstacleSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingGui::showObstacleSettings );
201 
202  mFieldExpressionWidget->registerExpressionContextGenerator( this );
203 
204  mMinScaleWidget->setMapCanvas( mCanvas );
205  mMinScaleWidget->setShowCurrentScaleButton( true );
206  mMaxScaleWidget->setMapCanvas( mCanvas );
207  mMaxScaleWidget->setShowCurrentScaleButton( true );
208 
209  const QStringList calloutTypes = QgsApplication::calloutRegistry()->calloutTypes();
210  for ( const QString &type : calloutTypes )
211  {
212  mCalloutStyleComboBox->addItem( QgsApplication::calloutRegistry()->calloutMetadata( type )->icon(),
213  QgsApplication::calloutRegistry()->calloutMetadata( type )->visibleName(), type );
214  }
215 
216  mGeometryGeneratorWarningLabel->setStyleSheet( QStringLiteral( "color: #FFC107;" ) );
217  mGeometryGeneratorWarningLabel->setTextInteractionFlags( Qt::TextBrowserInteraction );
218  connect( mGeometryGeneratorWarningLabel, &QLabel::linkActivated, this, [this]( const QString & link )
219  {
220  if ( link == QLatin1String( "#determineGeometryGeneratorType" ) )
221  determineGeometryGeneratorType();
222  } );
223 
224  connect( mCalloutStyleComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::calloutTypeChanged );
225 
226  setLayer( layer );
227 }
228 
229 void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
230 {
231  mPreviewFeature = QgsFeature();
232 
233  if ( ( !mapLayer || mapLayer->type() != QgsMapLayerType::VectorLayer ) && mGeomType == QgsWkbTypes::UnknownGeometry )
234  {
235  setEnabled( false );
236  return;
237  }
238 
239  setEnabled( true );
240 
241  QgsVectorLayer *layer = static_cast<QgsVectorLayer *>( mapLayer );
242  mLayer = layer;
243 
244  mTextFormatsListWidget->setLayerType( mLayer ? mLayer->geometryType() : mGeomType );
245  mBackgroundSymbolButton->setLayer( mLayer );
246 
247  // load labeling settings from layer
248  updateGeometryTypeBasedWidgets();
249 
250  mFieldExpressionWidget->setLayer( mLayer );
251  QgsDistanceArea da;
252  if ( mLayer )
253  da.setSourceCrs( mLayer->crs(), QgsProject::instance()->transformContext() );
254  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
255  mFieldExpressionWidget->setGeomCalculator( da );
256 
257  mFieldExpressionWidget->setEnabled( mMode == Labels || !mLayer );
258  mLabelingFrame->setEnabled( mMode == Labels || !mLayer );
259 
260  blockInitSignals( true );
261 
262  mGeometryGenerator->setText( mSettings.geometryGenerator );
263  mGeometryGeneratorGroupBox->setChecked( mSettings.geometryGeneratorEnabled );
264  mGeometryGeneratorType->setCurrentIndex( mGeometryGeneratorType->findData( mSettings.geometryGeneratorType ) );
265 
266  updateWidgetForFormat( mSettings.format() );
267 
268  mFieldExpressionWidget->setRow( -1 );
269  mFieldExpressionWidget->setField( mSettings.fieldName );
270  mCheckBoxSubstituteText->setChecked( mSettings.useSubstitutions );
271  mSubstitutions = mSettings.substitutions;
272 
273  // populate placement options
274  mCentroidRadioWhole->setChecked( mSettings.centroidWhole );
275  mCentroidInsideCheckBox->setChecked( mSettings.centroidInside );
276  mFitInsidePolygonCheckBox->setChecked( mSettings.fitInPolygonOnly );
277  mLineDistanceSpnBx->setValue( mSettings.dist );
278  mLineDistanceUnitWidget->setUnit( mSettings.distUnits );
279  mLineDistanceUnitWidget->setMapUnitScale( mSettings.distMapUnitScale );
280  mOffsetTypeComboBox->setCurrentIndex( mOffsetTypeComboBox->findData( mSettings.offsetType ) );
281  mQuadrantBtnGrp->button( static_cast<int>( mSettings.quadOffset ) )->setChecked( true );
282  mPointOffsetXSpinBox->setValue( mSettings.xOffset );
283  mPointOffsetYSpinBox->setValue( mSettings.yOffset );
284  mPointOffsetUnitWidget->setUnit( mSettings.offsetUnits );
285  mPointOffsetUnitWidget->setMapUnitScale( mSettings.labelOffsetMapUnitScale );
286  mPointAngleSpinBox->setValue( mSettings.angleOffset );
287  chkLineAbove->setChecked( mSettings.placementFlags & QgsPalLayerSettings::AboveLine );
288  chkLineBelow->setChecked( mSettings.placementFlags & QgsPalLayerSettings::BelowLine );
289  chkLineOn->setChecked( mSettings.placementFlags & QgsPalLayerSettings::OnLine );
290  chkLineOrientationDependent->setChecked( !( mSettings.placementFlags & QgsPalLayerSettings::MapOrientation ) );
291 
292  switch ( mSettings.placement )
293  {
295  radAroundPoint->setChecked( true );
296  radAroundCentroid->setChecked( true );
297  //spinAngle->setValue( lyr.angle ); // TODO: uncomment when supported
298  break;
300  radOverPoint->setChecked( true );
301  radOverCentroid->setChecked( true );
302  break;
304  radPredefinedOrder->setChecked( true );
305  break;
307  radLineParallel->setChecked( true );
308  radPolygonPerimeter->setChecked( true );
309  break;
311  radLineCurved->setChecked( true );
312  break;
314  radPolygonHorizontal->setChecked( true );
315  radLineHorizontal->setChecked( true );
316  break;
318  radPolygonFree->setChecked( true );
319  break;
321  radPolygonPerimeterCurved->setChecked( true );
322  break;
323  }
324 
325  // Label repeat distance
326  mRepeatDistanceSpinBox->setValue( mSettings.repeatDistance );
327  mRepeatDistanceUnitWidget->setUnit( mSettings.repeatDistanceUnit );
328  mRepeatDistanceUnitWidget->setMapUnitScale( mSettings.repeatDistanceMapUnitScale );
329 
330  mOverrunDistanceSpinBox->setValue( mSettings.overrunDistance );
331  mOverrunDistanceUnitWidget->setUnit( mSettings.overrunDistanceUnit );
332  mOverrunDistanceUnitWidget->setMapUnitScale( mSettings.overrunDistanceMapUnitScale );
333 
334  mPrioritySlider->setValue( mSettings.priority );
335  mChkNoObstacle->setChecked( mSettings.obstacleSettings().isObstacle() );
336 
337  mObstacleSettings = mSettings.obstacleSettings();
338 
339  chkLabelPerFeaturePart->setChecked( mSettings.labelPerPart );
340  mPalShowAllLabelsForLayerChkBx->setChecked( mSettings.displayAll );
341  chkMergeLines->setChecked( mSettings.mergeLines );
342  mMinSizeSpinBox->setValue( mSettings.thinningSettings().minimumFeatureSize() );
343  mLimitLabelChkBox->setChecked( mSettings.thinningSettings().limitNumberOfLabelsEnabled() );
344  mLimitLabelSpinBox->setValue( mSettings.thinningSettings().maximumNumberLabels() );
345 
346  // direction symbol(s)
347  mDirectSymbChkBx->setChecked( mSettings.addDirectionSymbol );
348  mDirectSymbLeftLineEdit->setText( mSettings.leftDirectionSymbol );
349  mDirectSymbRightLineEdit->setText( mSettings.rightDirectionSymbol );
350  mDirectSymbRevChkBx->setChecked( mSettings.reverseDirectionSymbol );
351 
352  mDirectSymbBtnGrp->button( static_cast<int>( mSettings.placeDirectionSymbol ) )->setChecked( true );
353  mUpsidedownBtnGrp->button( static_cast<int>( mSettings.upsidedownLabels ) )->setChecked( true );
354 
355  // curved label max character angles
356  mMaxCharAngleInDSpinBox->setValue( mSettings.maxCurvedCharAngleIn );
357  // lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
358  mMaxCharAngleOutDSpinBox->setValue( std::fabs( mSettings.maxCurvedCharAngleOut ) );
359 
360  wrapCharacterEdit->setText( mSettings.wrapChar );
361  mAutoWrapLengthSpinBox->setValue( mSettings.autoWrapLength );
362  mAutoWrapTypeComboBox->setCurrentIndex( mSettings.useMaxLineLengthForAutoWrap ? 0 : 1 );
363 
364  if ( ( int ) mSettings.multilineAlign < mFontMultiLineAlignComboBox->count() )
365  {
366  mFontMultiLineAlignComboBox->setCurrentIndex( mSettings.multilineAlign );
367  }
368  else
369  {
370  // the default pal layer settings for multiline alignment is to follow label placement, which isn't always available
371  // revert to left alignment in such case
372  mFontMultiLineAlignComboBox->setCurrentIndex( 0 );
373  }
374 
375  chkPreserveRotation->setChecked( mSettings.preserveRotation );
376 
377  mScaleBasedVisibilityChkBx->setChecked( mSettings.scaleVisibility );
378  mMinScaleWidget->setScale( mSettings.minimumScale );
379  mMaxScaleWidget->setScale( mSettings.maximumScale );
380 
381  mFormatNumChkBx->setChecked( mSettings.formatNumbers );
382  mFormatNumDecimalsSpnBx->setValue( mSettings.decimals );
383  mFormatNumPlusSignChkBx->setChecked( mSettings.plusSign );
384 
385  // set pixel size limiting checked state before unit choice so limiting can be
386  // turned on as a default for map units, if minimum trigger value of 0 is used
387  mFontLimitPixelChkBox->setChecked( mSettings.fontLimitPixelSize );
388  mMinPixelLimit = mSettings.fontMinPixelSize; // ignored after first settings save
389  mFontMinPixelSpinBox->setValue( mSettings.fontMinPixelSize == 0 ? 3 : mSettings.fontMinPixelSize );
390  mFontMaxPixelSpinBox->setValue( mSettings.fontMaxPixelSize );
391 
392  mZIndexSpinBox->setValue( mSettings.zIndex );
393 
394  mDataDefinedProperties = mSettings.dataDefinedProperties();
395 
396  // callout settings, to move to custom widget when multiple styles exist
397  if ( mSettings.callout() )
398  {
399  whileBlocking( mCalloutsDrawCheckBox )->setChecked( mSettings.callout()->enabled() );
400  whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( mSettings.callout()->type() ) );
401  updateCalloutWidget( mSettings.callout() );
402  }
403  else
404  {
405  std::unique_ptr< QgsCallout > defaultCallout( QgsApplication::calloutRegistry()->defaultCallout() );
406  whileBlocking( mCalloutStyleComboBox )->setCurrentIndex( mCalloutStyleComboBox->findData( defaultCallout->type() ) );
407  whileBlocking( mCalloutsDrawCheckBox )->setChecked( false );
408  updateCalloutWidget( defaultCallout.get() );
409  }
410 
411  updatePlacementWidgets();
412  updateLinePlacementOptions();
413 
414  // needs to come before data defined setup, so connections work
415  blockInitSignals( false );
416 
417  // set up data defined toolbuttons
418  // do this after other widgets are configured, so they can be enabled/disabled
419  populateDataDefinedButtons();
420 
421  enableDataDefinedAlignment( mCoordXDDBtn->isActive() && mCoordYDDBtn->isActive() );
422  updateUi(); // should come after data defined button setup
423 }
424 
425 void QgsLabelingGui::setSettings( const QgsPalLayerSettings &settings )
426 {
427  mSettings = settings;
428  setLayer( mLayer );
429 }
430 
431 void QgsLabelingGui::blockInitSignals( bool block )
432 {
433  chkLineAbove->blockSignals( block );
434  chkLineBelow->blockSignals( block );
435  mPlacePointBtnGrp->blockSignals( block );
436  mPlaceLineBtnGrp->blockSignals( block );
437  mPlacePolygonBtnGrp->blockSignals( block );
438 }
439 
440 void QgsLabelingGui::setLabelMode( LabelMode mode )
441 {
442  mMode = mode;
443  mFieldExpressionWidget->setEnabled( mMode == Labels );
444  mLabelingFrame->setEnabled( mMode == Labels );
445 }
446 
447 QgsPalLayerSettings QgsLabelingGui::layerSettings()
448 {
450 
451  lyr.drawLabels = ( mMode == Labels ) || !mLayer;
452 
453  bool isExpression;
454  lyr.fieldName = mFieldExpressionWidget->currentField( &isExpression );
455  lyr.isExpression = isExpression;
456 
457  lyr.dist = 0;
458  lyr.placementFlags = 0;
459 
460  QWidget *curPlacementWdgt = stackedPlacement->currentWidget();
461  lyr.centroidWhole = mCentroidRadioWhole->isChecked();
462  lyr.centroidInside = mCentroidInsideCheckBox->isChecked();
463  lyr.fitInPolygonOnly = mFitInsidePolygonCheckBox->isChecked();
464  lyr.dist = mLineDistanceSpnBx->value();
465  lyr.distUnits = mLineDistanceUnitWidget->unit();
466  lyr.distMapUnitScale = mLineDistanceUnitWidget->getMapUnitScale();
467  lyr.offsetType = static_cast< QgsPalLayerSettings::OffsetType >( mOffsetTypeComboBox->currentData().toInt() );
468  if ( mQuadrantBtnGrp )
469  {
470  lyr.quadOffset = ( QgsPalLayerSettings::QuadrantPosition )mQuadrantBtnGrp->checkedId();
471  }
472  lyr.xOffset = mPointOffsetXSpinBox->value();
473  lyr.yOffset = mPointOffsetYSpinBox->value();
474  lyr.offsetUnits = mPointOffsetUnitWidget->unit();
475  lyr.labelOffsetMapUnitScale = mPointOffsetUnitWidget->getMapUnitScale();
476  lyr.angleOffset = mPointAngleSpinBox->value();
477  if ( chkLineAbove->isChecked() )
479  if ( chkLineBelow->isChecked() )
481  if ( chkLineOn->isChecked() )
483  if ( ! chkLineOrientationDependent->isChecked() )
485  if ( ( curPlacementWdgt == pagePoint && radAroundPoint->isChecked() )
486  || ( curPlacementWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
487  {
489  }
490  else if ( ( curPlacementWdgt == pagePoint && radOverPoint->isChecked() )
491  || ( curPlacementWdgt == pagePolygon && radOverCentroid->isChecked() ) )
492  {
494  }
495  else if ( curPlacementWdgt == pagePoint && radPredefinedOrder->isChecked() )
496  {
498  }
499  else if ( ( curPlacementWdgt == pageLine && radLineParallel->isChecked() )
500  || ( curPlacementWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) )
501  {
503  }
504  else if ( curPlacementWdgt == pageLine && radLineCurved->isChecked() )
505  {
507  }
508  else if ( curPlacementWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() )
509  {
511  }
512  else if ( ( curPlacementWdgt == pageLine && radLineHorizontal->isChecked() )
513  || ( curPlacementWdgt == pagePolygon && radPolygonHorizontal->isChecked() ) )
514  {
516  }
517  else if ( radPolygonFree->isChecked() )
518  {
520  }
521  else
522  {
523  qFatal( "Invalid settings" );
524  }
525 
526  lyr.repeatDistance = mRepeatDistanceSpinBox->value();
527  lyr.repeatDistanceUnit = mRepeatDistanceUnitWidget->unit();
528  lyr.repeatDistanceMapUnitScale = mRepeatDistanceUnitWidget->getMapUnitScale();
529 
530  lyr.overrunDistance = mOverrunDistanceSpinBox->value();
531  lyr.overrunDistanceUnit = mOverrunDistanceUnitWidget->unit();
532  lyr.overrunDistanceMapUnitScale = mOverrunDistanceUnitWidget->getMapUnitScale();
533 
534  lyr.priority = mPrioritySlider->value();
535 
536  mObstacleSettings.setIsObstacle( mChkNoObstacle->isChecked() || mMode == ObstaclesOnly );
537  lyr.setObstacleSettings( mObstacleSettings );
538 
539  lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
540  lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
541  lyr.mergeLines = chkMergeLines->isChecked();
542 
543  lyr.scaleVisibility = mScaleBasedVisibilityChkBx->isChecked();
544  lyr.minimumScale = mMinScaleWidget->scale();
545  lyr.maximumScale = mMaxScaleWidget->scale();
546  lyr.useSubstitutions = mCheckBoxSubstituteText->isChecked();
547  lyr.substitutions = mSubstitutions;
548 
549  lyr.setFormat( format( false ) );
550 
551  // format numbers
552  lyr.formatNumbers = mFormatNumChkBx->isChecked();
553  lyr.decimals = mFormatNumDecimalsSpnBx->value();
554  lyr.plusSign = mFormatNumPlusSignChkBx->isChecked();
555 
556  // direction symbol(s)
557  lyr.addDirectionSymbol = mDirectSymbChkBx->isChecked();
558  lyr.leftDirectionSymbol = mDirectSymbLeftLineEdit->text();
559  lyr.rightDirectionSymbol = mDirectSymbRightLineEdit->text();
560  lyr.reverseDirectionSymbol = mDirectSymbRevChkBx->isChecked();
561  if ( mDirectSymbBtnGrp )
562  {
563  lyr.placeDirectionSymbol = ( QgsPalLayerSettings::DirectionSymbols )mDirectSymbBtnGrp->checkedId();
564  }
565  if ( mUpsidedownBtnGrp )
566  {
567  lyr.upsidedownLabels = ( QgsPalLayerSettings::UpsideDownLabels )mUpsidedownBtnGrp->checkedId();
568  }
569 
570  lyr.maxCurvedCharAngleIn = mMaxCharAngleInDSpinBox->value();
571  // lyr.maxCurvedCharAngleOut must be negative, but it is shown as positive spinbox in GUI
572  lyr.maxCurvedCharAngleOut = -mMaxCharAngleOutDSpinBox->value();
573 
574 
575  lyr.thinningSettings().setMinimumFeatureSize( mMinSizeSpinBox->value() );
576  lyr.thinningSettings().setLimitNumberLabelsEnabled( mLimitLabelChkBox->isChecked() );
577  lyr.thinningSettings().setMaximumNumberLabels( mLimitLabelSpinBox->value() );
578  lyr.fontLimitPixelSize = mFontLimitPixelChkBox->isChecked();
579  lyr.fontMinPixelSize = mFontMinPixelSpinBox->value();
580  lyr.fontMaxPixelSize = mFontMaxPixelSpinBox->value();
581  lyr.wrapChar = wrapCharacterEdit->text();
582  lyr.autoWrapLength = mAutoWrapLengthSpinBox->value();
583  lyr.useMaxLineLengthForAutoWrap = mAutoWrapTypeComboBox->currentIndex() == 0;
584  lyr.multilineAlign = ( QgsPalLayerSettings::MultiLineAlign ) mFontMultiLineAlignComboBox->currentIndex();
585  lyr.preserveRotation = chkPreserveRotation->isChecked();
586  lyr.geometryGenerator = mGeometryGenerator->text();
587  lyr.geometryGeneratorType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
588  lyr.geometryGeneratorEnabled = mGeometryGeneratorGroupBox->isChecked();
589 
590  lyr.layerType = mLayer ? mLayer->geometryType() : mGeomType;
591 
592  lyr.zIndex = mZIndexSpinBox->value();
593 
594  lyr.setDataDefinedProperties( mDataDefinedProperties );
595 
596  // callout settings
597  const QString calloutType = mCalloutStyleComboBox->currentData().toString();
598  std::unique_ptr< QgsCallout > callout;
599  if ( QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
600  {
601  callout.reset( pew->callout()->clone() );
602  }
603  if ( !callout )
604  callout.reset( QgsApplication::calloutRegistry()->createCallout( calloutType ) );
605 
606  callout->setEnabled( mCalloutsDrawCheckBox->isChecked() );
607  lyr.setCallout( callout.release() );
608 
609  return lyr;
610 }
611 
612 void QgsLabelingGui::syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f )
613 {
614  if ( ddBtn->isActive() && !chkBx->isChecked() )
615  {
616  chkBx->setChecked( true );
617  }
618  f->setEnabled( chkBx->isChecked() );
619 }
620 
621 void QgsLabelingGui::updateUi()
622 {
623  // enable/disable inline groupbox-like setups (that need to honor data defined setting)
624 
625  syncDefinedCheckboxFrame( mBufferDrawDDBtn, mBufferDrawChkBx, mBufferFrame );
626  syncDefinedCheckboxFrame( mEnableMaskDDBtn, mEnableMaskChkBx, mMaskFrame );
627  syncDefinedCheckboxFrame( mShapeDrawDDBtn, mShapeDrawChkBx, mShapeFrame );
628  syncDefinedCheckboxFrame( mShadowDrawDDBtn, mShadowDrawChkBx, mShadowFrame );
629 
630  syncDefinedCheckboxFrame( mDirectSymbDDBtn, mDirectSymbChkBx, mDirectSymbFrame );
631  syncDefinedCheckboxFrame( mFormatNumDDBtn, mFormatNumChkBx, mFormatNumFrame );
632  syncDefinedCheckboxFrame( mScaleBasedVisibilityDDBtn, mScaleBasedVisibilityChkBx, mScaleBasedVisibilityFrame );
633  syncDefinedCheckboxFrame( mFontLimitPixelDDBtn, mFontLimitPixelChkBox, mFontLimitPixelFrame );
634 
635  chkMergeLines->setEnabled( !mDirectSymbChkBx->isChecked() );
636  if ( mDirectSymbChkBx->isChecked() )
637  {
638  chkMergeLines->setToolTip( tr( "This option is not compatible with line direction symbols." ) );
639  }
640  else
641  {
642  chkMergeLines->setToolTip( QString() );
643  }
644 }
645 
646 void QgsLabelingGui::setFormatFromStyle( const QString &name, QgsStyle::StyleEntity type )
647 {
648  switch ( type )
649  {
652  case QgsStyle::TagEntity:
655  {
657  return;
658  }
659 
661  {
662  if ( !QgsStyle::defaultStyle()->labelSettingsNames().contains( name ) )
663  return;
664 
666  if ( settings.fieldName.isEmpty() )
667  {
668  // if saved settings doesn't have a field name stored, retain the current one
669  bool isExpression;
670  settings.fieldName = mFieldExpressionWidget->currentField( &isExpression );
671  settings.isExpression = isExpression;
672  }
673  setSettings( settings );
674  break;
675  }
676  }
677 }
678 
679 void QgsLabelingGui::setContext( const QgsSymbolWidgetContext &context )
680 {
681  if ( QgsCalloutWidget *cw = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() ) )
682  {
683  cw->setContext( context );
684  }
686 }
687 
688 void QgsLabelingGui::saveFormat()
689 {
690  QgsStyle *style = QgsStyle::defaultStyle();
691  if ( !style )
692  return;
693 
694  QgsStyleSaveDialog saveDlg( this, QgsStyle::LabelSettingsEntity );
695  saveDlg.setDefaultTags( mTextFormatsListWidget->currentTagFilter() );
696  if ( !saveDlg.exec() )
697  return;
698 
699  if ( saveDlg.name().isEmpty() )
700  return;
701 
702  switch ( saveDlg.selectedType() )
703  {
705  {
706  // check if there is no format with same name
707  if ( style->textFormatNames().contains( saveDlg.name() ) )
708  {
709  int res = QMessageBox::warning( this, tr( "Save Text Format" ),
710  tr( "Format with name '%1' already exists. Overwrite?" )
711  .arg( saveDlg.name() ),
712  QMessageBox::Yes | QMessageBox::No );
713  if ( res != QMessageBox::Yes )
714  {
715  return;
716  }
717  style->removeTextFormat( saveDlg.name() );
718  }
719  QStringList symbolTags = saveDlg.tags().split( ',' );
720 
721  QgsTextFormat newFormat = format();
722  style->addTextFormat( saveDlg.name(), newFormat );
723  style->saveTextFormat( saveDlg.name(), newFormat, saveDlg.isFavorite(), symbolTags );
724  break;
725  }
726 
728  {
729  // check if there is no settings with same name
730  if ( style->labelSettingsNames().contains( saveDlg.name() ) )
731  {
732  int res = QMessageBox::warning( this, tr( "Save Label Settings" ),
733  tr( "Label settings with the name '%1' already exist. Overwrite?" )
734  .arg( saveDlg.name() ),
735  QMessageBox::Yes | QMessageBox::No );
736  if ( res != QMessageBox::Yes )
737  {
738  return;
739  }
740  style->removeLabelSettings( saveDlg.name() );
741  }
742  QStringList symbolTags = saveDlg.tags().split( ',' );
743 
744  QgsPalLayerSettings newSettings = layerSettings();
745  style->addLabelSettings( saveDlg.name(), newSettings );
746  style->saveLabelSettings( saveDlg.name(), newSettings, saveDlg.isFavorite(), symbolTags );
747  break;
748  }
749 
752  case QgsStyle::TagEntity:
754  break;
755  }
756 }
757 
758 void QgsLabelingGui::updateGeometryTypeBasedWidgets()
759 {
760  QgsWkbTypes::GeometryType geometryType = mGeomType;
761 
762  if ( mGeometryGeneratorGroupBox->isChecked() )
763  geometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
764  else if ( mLayer )
765  geometryType = mLayer->geometryType();
766 
767  // show/hide options based upon geometry type
768  chkMergeLines->setVisible( geometryType == QgsWkbTypes::LineGeometry );
769  mDirectSymbolsFrame->setVisible( geometryType == QgsWkbTypes::LineGeometry );
770  mMinSizeFrame->setVisible( geometryType != QgsWkbTypes::PointGeometry );
771  mPolygonFeatureOptionsFrame->setVisible( geometryType == QgsWkbTypes::PolygonGeometry );
772 
773 
774  // set placement methods page based on geometry type
775  switch ( geometryType )
776  {
778  stackedPlacement->setCurrentWidget( pagePoint );
779  break;
781  stackedPlacement->setCurrentWidget( pageLine );
782  break;
784  stackedPlacement->setCurrentWidget( pagePolygon );
785  break;
787  break;
789  qFatal( "unknown geometry type unexpected" );
790  }
791 
792  if ( geometryType == QgsWkbTypes::PointGeometry )
793  {
794  // follow placement alignment is only valid for point layers
795  if ( mFontMultiLineAlignComboBox->findText( tr( "Follow label placement" ) ) == -1 )
796  mFontMultiLineAlignComboBox->addItem( tr( "Follow label placement" ) );
797  }
798  else
799  {
800  int idx = mFontMultiLineAlignComboBox->findText( tr( "Follow label placement" ) );
801  if ( idx >= 0 )
802  mFontMultiLineAlignComboBox->removeItem( idx );
803  }
804 
805  updatePlacementWidgets();
806  updateLinePlacementOptions();
807 }
808 
809 void QgsLabelingGui::showGeometryGeneratorExpressionBuilder()
810 {
811  QgsExpressionBuilderDialog expressionBuilder( mLayer );
812 
813  expressionBuilder.setExpressionText( mGeometryGenerator->text() );
814  expressionBuilder.setExpressionContext( createExpressionContext() );
815 
816  if ( expressionBuilder.exec() )
817  {
818  mGeometryGenerator->setText( expressionBuilder.expressionText() );
819  }
820 }
821 
822 void QgsLabelingGui::validateGeometryGeneratorExpression()
823 {
824  bool valid = true;
825 
826  if ( mGeometryGeneratorGroupBox->isChecked() )
827  {
828  if ( !mPreviewFeature.isValid() && mLayer )
829  mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
830 
831  QgsExpression expression( mGeometryGenerator->text() );
832  QgsExpressionContext context = createExpressionContext();
833  context.setFeature( mPreviewFeature );
834 
835  expression.prepare( &context );
836 
837  if ( expression.hasParserError() )
838  {
839  mGeometryGeneratorWarningLabel->setText( expression.parserErrorString() );
840  valid = false;
841  }
842  else
843  {
844  const QVariant result = expression.evaluate( &context );
845  const QgsGeometry geometry = result.value<QgsGeometry>();
846  QgsWkbTypes::GeometryType configuredGeometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
847  if ( geometry.isNull() )
848  {
849  mGeometryGeneratorWarningLabel->setText( tr( "Result of the expression is not a geometry" ) );
850  valid = false;
851  }
852  else if ( geometry.type() != configuredGeometryType )
853  {
854  mGeometryGeneratorWarningLabel->setText( QStringLiteral( "<p>%1</p><p><a href=\"#determineGeometryGeneratorType\">%2</a></p>" ).arg(
855  tr( "Result of the expression does not match configured geometry type." ),
856  tr( "Change to %1" ).arg( QgsWkbTypes::geometryDisplayString( geometry.type() ) ) ) );
857  valid = false;
858  }
859  }
860  }
861 
862  // The collapsible groupbox internally changes the visibility of this
863  // Work around by setting the visibility deferred in the next event loop cycle.
864  QTimer *timer = new QTimer();
865  connect( timer, &QTimer::timeout, this, [this, valid]()
866  {
867  mGeometryGeneratorWarningLabel->setVisible( !valid );
868  } );
869  connect( timer, &QTimer::timeout, timer, &QTimer::deleteLater );
870  timer->start( 0 );
871 }
872 
873 void QgsLabelingGui::determineGeometryGeneratorType()
874 {
875  if ( !mPreviewFeature.isValid() && mLayer )
876  mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
877 
878  QgsExpression expression( mGeometryGenerator->text() );
879  QgsExpressionContext context = createExpressionContext();
880  context.setFeature( mPreviewFeature );
881 
882  expression.prepare( &context );
883  const QgsGeometry geometry = expression.evaluate( &context ).value<QgsGeometry>();
884 
885  mGeometryGeneratorType->setCurrentIndex( mGeometryGeneratorType->findData( geometry.type() ) );
886 }
887 
888 void QgsLabelingGui::calloutTypeChanged()
889 {
890  QString newCalloutType = mCalloutStyleComboBox->currentData().toString();
891  QgsCalloutWidget *pew = qobject_cast< QgsCalloutWidget * >( mCalloutStackedWidget->currentWidget() );
892  if ( pew )
893  {
894  if ( pew->callout() && pew->callout()->type() == newCalloutType )
895  return;
896  }
897 
898  // get creation function for new callout from registry
900  QgsCalloutAbstractMetadata *am = registry->calloutMetadata( newCalloutType );
901  if ( !am ) // check whether the metadata is assigned
902  return;
903 
904  // change callout to a new one (with different type)
905  // base new callout on existing callout's properties
906  std::unique_ptr< QgsCallout > newCallout( am->createCallout( pew && pew->callout() ? pew->callout()->properties( QgsReadWriteContext() ) : QVariantMap(), QgsReadWriteContext() ) );
907  if ( !newCallout )
908  return;
909 
910  updateCalloutWidget( newCallout.get() );
911  updatePreview();
912 }
913 
914 
915 //
916 // QgsLabelSettingsDialog
917 //
918 
919 QgsLabelSettingsDialog::QgsLabelSettingsDialog( const QgsPalLayerSettings &settings, QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, QWidget *parent,
920  QgsWkbTypes::GeometryType geomType )
921  : QDialog( parent )
922 {
923  QVBoxLayout *vLayout = new QVBoxLayout();
924  mWidget = new QgsLabelingGui( layer, mapCanvas, settings, nullptr, geomType );
925  vLayout->addWidget( mWidget );
926  mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok, Qt::Horizontal );
927  connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
928  connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
929  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsLabelSettingsDialog::showHelp );
930  vLayout->addWidget( mButtonBox );
931  setLayout( vLayout );
932  setWindowTitle( tr( "Label Settings" ) );
933 }
934 
935 QDialogButtonBox *QgsLabelSettingsDialog::buttonBox() const
936 {
937  return mButtonBox;
938 }
939 
940 void QgsLabelSettingsDialog::showHelp()
941 {
942  QgsHelp::openHelp( QStringLiteral( "style_library/label_settings.html" ) );
943 }
944 
945 
946 
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").
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
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.
bool dockMode()
Returns the dock mode state.
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.
#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.
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 ...
Base class for any widget that can be shown as a inline panel.
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.
void setMaximumNumberLabels(int number)
Sets the maximum number of labels which should be drawn for this layer.
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.
void setGeometryType(QgsWkbTypes::GeometryType type) override
Sets the geometry type of the features to customize the widget accordingly.
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.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
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...
void updateDataDefinedProperties(QgsPropertyCollection &properties) override
Updates a data defined properties collection, correctly setting the values for any properties related...
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
A widget for customising label obstacle settings.
A blocking dialog containing a QgsLabelSettingsWidgetBase.
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.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget...
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...
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
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.
void setDataDefinedProperties(const QgsPropertyCollection &dataDefinedProperties)
Sets the current data defined properties to show in the widget.
void setSettings(const QgsLabelObstacleSettings &settings)
Sets the obstacle settings to show in the widget.
void setObstacleSettings(const QgsLabelObstacleSettings &settings)
Sets the label obstacle settings.
void setLimitNumberLabelsEnabled(bool enabled)
Sets whether the the number of labels drawn for the layer should be limited.
QgsPropertyCollection dataDefinedProperties() const
Returns the current data defined properties state as specified in the widget.
void setExpressionContext(QgsExpressionContext *context)
Sets the optional expression context used for the widget.
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:98
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:262
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:450
double dist
Distance from feature to the label.
const QgsLabelThinningSettings & thinningSettings() const
Returns the label thinning settings.
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.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
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;
void changed()
Emitted when any of the settings described by the widget are changed.
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.
void setMinimumFeatureSize(double size)
Sets the minimum feature size (in millimeters) for a feature to be labelled.
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.
bool removeLabelSettings(const QString &name)
Removes label settings from the style.
Definition: qgsstyle.cpp:833
QgsLabelObstacleSettings settings() const
Returns the obstacle settings defined by the widget.
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.
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.