18#include <QCoreApplication> 
   42#include <QActionGroup> 
   50  , mMapCanvas( canvas )
 
   52  , mCommonAngleConstraint( 
QgsSettings().value( QStringLiteral( 
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
 
   58  mAngleConstraint.reset( 
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
 
   60  mAngleConstraint->setMapCanvas( mMapCanvas );
 
   61  mDistanceConstraint.reset( 
new CadConstraint( mDistanceLineEdit, mLockDistanceButton, 
nullptr, mRepeatingLockDistanceButton ) );
 
   63  mDistanceConstraint->setMapCanvas( mMapCanvas );
 
   64  mXConstraint.reset( 
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
 
   66  mXConstraint->setMapCanvas( mMapCanvas );
 
   67  mYConstraint.reset( 
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
 
   69  mYConstraint->setMapCanvas( mMapCanvas );
 
   70  mZConstraint.reset( 
new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
 
   72  mZConstraint->setMapCanvas( mMapCanvas );
 
   73  mMConstraint.reset( 
new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
 
   75  mMConstraint->setMapCanvas( mMapCanvas );
 
   77  mLineExtensionConstraint.reset( 
new CadConstraint( 
new QLineEdit(), 
new QToolButton() ) );
 
   78  mXyVertexConstraint.reset( 
new CadConstraint( 
new QLineEdit(), 
new QToolButton() ) );
 
   79  mXyVertexConstraint->setMapCanvas( mMapCanvas );
 
   83  mMapCanvas->installEventFilter( 
this );
 
   84  mAngleLineEdit->installEventFilter( 
this );
 
   85  mDistanceLineEdit->installEventFilter( 
this );
 
   86  mXLineEdit->installEventFilter( 
this );
 
   87  mYLineEdit->installEventFilter( 
this );
 
   88  mZLineEdit->installEventFilter( 
this );
 
   89  mMLineEdit->installEventFilter( 
this );
 
   92  connect( mEnableAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::activateCad );
 
   93  connect( mConstructionModeAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
 
   94  connect( mParallelAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
 
   95  connect( mPerpendicularAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
 
   96  connect( mLockAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
   97  connect( mLockDistanceButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
   98  connect( mLockXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
   99  connect( mLockYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  100  connect( mLockZButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  101  connect( mLockMButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  102  connect( mRelativeAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  103  connect( mRelativeXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  104  connect( mRelativeYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  105  connect( mRelativeZButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  106  connect( mRelativeMButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  107  connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  108  connect( mRepeatingLockAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  109  connect( mRepeatingLockXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  110  connect( mRepeatingLockYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  111  connect( mRepeatingLockZButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  112  connect( mRepeatingLockMButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  113  connect( mAngleLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
  114  connect( mDistanceLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
  115  connect( mXLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
  116  connect( mYLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
  117  connect( mZLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
  118  connect( mMLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
  119  connect( mAngleLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  120  connect( mDistanceLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  121  connect( mXLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  122  connect( mYLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  123  connect( mZLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  124  connect( mMLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  140  mCommonAngleActionsMenu = 
new QMenu( 
this );
 
  142#ifndef __clang_analyzer__ 
  143  QActionGroup *angleButtonGroup = 
new QActionGroup( mCommonAngleActionsMenu ); 
 
  145  mCommonAngleActions = QMap<QAction *, double>();
 
  146  QList< QPair< double, QString > > commonAngles;
 
  147  const QList<double> anglesDouble( { 0.0, 0.1, 0.5, 1.0, 5.0, 10.0, 15.0, 18.0, 22.5, 30.0, 45.0, 90.0} );
 
  148  for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
 
  154    QMenu *snappingPriorityMenu = 
new QMenu( tr( 
"Snapping Priority" ), mCommonAngleActionsMenu );
 
  155    QActionGroup *snappingPriorityActionGroup = 
new QActionGroup( snappingPriorityMenu );
 
  156    QAction *featuresAction = 
new QAction( tr( 
"Prioritize Snapping to Features" ), snappingPriorityActionGroup );
 
  157    featuresAction->setCheckable( 
true );
 
  158    QAction *anglesAction = 
new QAction( tr( 
"Prioritize Snapping to Angle" ), snappingPriorityActionGroup );
 
  159    anglesAction->setCheckable( 
true );
 
  160    snappingPriorityActionGroup->addAction( featuresAction );
 
  161    snappingPriorityActionGroup->addAction( anglesAction );
 
  162    snappingPriorityMenu->addAction( anglesAction );
 
  163    snappingPriorityMenu->addAction( featuresAction );
 
  164    connect( anglesAction, &QAction::changed, 
this, [ = ]
 
  166      mSnappingPrioritizeFeatures = featuresAction->isChecked();
 
  167      settingsCadSnappingPriorityPrioritizeFeature->
setValue( featuresAction->isChecked() );
 
  169    featuresAction->setChecked( settingsCadSnappingPriorityPrioritizeFeature->
value( ) );
 
  170    anglesAction->setChecked( ! featuresAction->isChecked() );
 
  171    mCommonAngleActionsMenu->addMenu( snappingPriorityMenu );
 
  175  for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
 
  177    QAction *action = 
new QAction( it->second, mCommonAngleActionsMenu );
 
  178    action->setCheckable( 
true );
 
  179    action->setChecked( it->first == mCommonAngleConstraint );
 
  180    mCommonAngleActionsMenu->addAction( action );
 
  182#ifndef __clang_analyzer__ 
  183    angleButtonGroup->addAction( action );
 
  185    mCommonAngleActions.insert( action, it->first );
 
  188  qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
 
  189  mSettingsAction->setMenu( mCommonAngleActionsMenu );
 
  190  mSettingsAction->setCheckable( 
true );
 
  191  mSettingsAction->setToolTip( 
"<b>" + tr( 
"Snap to common angles" ) + 
"</b><br>(" + tr( 
"press n to cycle through the options" ) + 
")" );
 
  192  mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
 
  193  connect( mCommonAngleActionsMenu, &QMenu::triggered, 
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
 
  196  QMenu *constructionMenu = 
new QMenu( 
this );
 
  198  mLineExtensionAction = 
new QAction( 
"Line Extension", constructionMenu );
 
  199  mLineExtensionAction->setCheckable( 
true );
 
  200  constructionMenu->addAction( mLineExtensionAction );
 
  201  connect( mLineExtensionAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
 
  203  mXyVertexAction = 
new QAction( 
"X/Y Point", constructionMenu );
 
  204  mXyVertexAction->setCheckable( 
true );
 
  205  constructionMenu->addAction( mXyVertexAction );
 
  206  connect( mXyVertexAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
 
  208  auto constructionToolBar = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionAction ) );
 
  209  constructionToolBar->setPopupMode( QToolButton::InstantPopup );
 
  210  constructionToolBar->setMenu( constructionMenu );
 
  211  constructionToolBar->setObjectName( QStringLiteral( 
"ConstructionButton" ) );
 
  213  mConstructionAction->setMenu( mCommonAngleActionsMenu );
 
  214  mConstructionAction->setCheckable( 
true );
 
  215  mConstructionAction->setToolTip( tr( 
"Construction Tools" ) );
 
  219  mConstructionModeAction->setToolTip( 
"<b>" + tr( 
"Construction mode" ) + 
"</b><br>(" + tr( 
"press c to toggle on/off" ) + 
")" );
 
  220  mDistanceLineEdit->setToolTip( 
"<b>" + tr( 
"Distance" ) + 
"</b><br>(" + tr( 
"press d for quick access" ) + 
")" );
 
  221  mLockDistanceButton->setToolTip( 
"<b>" + tr( 
"Lock distance" ) + 
"</b><br>(" + tr( 
"press Ctrl + d for quick access" ) + 
")" );
 
  222  mRepeatingLockDistanceButton->setToolTip( 
"<b>" + tr( 
"Continuously lock distance" ) + 
"</b>" );
 
  224  mRelativeAngleButton->setToolTip( 
"<b>" + tr( 
"Toggles relative angle to previous segment" ) + 
"</b><br>(" + tr( 
"press Shift + a for quick access" ) + 
")" );
 
  225  mAngleLineEdit->setToolTip( 
"<b>" + tr( 
"Angle" ) + 
"</b><br>(" + tr( 
"press a for quick access" ) + 
")" );
 
  226  mLockAngleButton->setToolTip( 
"<b>" + tr( 
"Lock angle" ) + 
"</b><br>(" + tr( 
"press Ctrl + a for quick access" ) + 
")" );
 
  227  mRepeatingLockAngleButton->setToolTip( 
"<b>" + tr( 
"Continuously lock angle" ) + 
"</b>" );
 
  229  mRelativeXButton->setToolTip( 
"<b>" + tr( 
"Toggles relative x to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + x for quick access" ) + 
")" );
 
  230  mXLineEdit->setToolTip( 
"<b>" + tr( 
"X coordinate" ) + 
"</b><br>(" + tr( 
"press x for quick access" ) + 
")" );
 
  231  mLockXButton->setToolTip( 
"<b>" + tr( 
"Lock x coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + x for quick access" ) + 
")" );
 
  232  mRepeatingLockXButton->setToolTip( 
"<b>" + tr( 
"Continuously lock x coordinate" ) + 
"</b>" );
 
  234  mRelativeYButton->setToolTip( 
"<b>" + tr( 
"Toggles relative y to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + y for quick access" ) + 
")" );
 
  235  mYLineEdit->setToolTip( 
"<b>" + tr( 
"Y coordinate" ) + 
"</b><br>(" + tr( 
"press y for quick access" ) + 
")" );
 
  236  mLockYButton->setToolTip( 
"<b>" + tr( 
"Lock y coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + y for quick access" ) + 
")" );
 
  237  mRepeatingLockYButton->setToolTip( 
"<b>" + tr( 
"Continuously lock y coordinate" ) + 
"</b>" );
 
  239  mRelativeZButton->setToolTip( 
"<b>" + tr( 
"Toggles relative z to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + z for quick access" ) + 
")" );
 
  240  mZLineEdit->setToolTip( 
"<b>" + tr( 
"Z coordinate" ) + 
"</b><br>(" + tr( 
"press z for quick access" ) + 
")" );
 
  241  mLockZButton->setToolTip( 
"<b>" + tr( 
"Lock z coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + z for quick access" ) + 
")" );
 
  242  mRepeatingLockZButton->setToolTip( 
"<b>" + tr( 
"Continuously lock z coordinate" ) + 
"</b>" );
 
  244  mRelativeMButton->setToolTip( 
"<b>" + tr( 
"Toggles relative m to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + m for quick access" ) + 
")" );
 
  245  mMLineEdit->setToolTip( 
"<b>" + tr( 
"M coordinate" ) + 
"</b><br>(" + tr( 
"press m for quick access" ) + 
")" );
 
  246  mLockMButton->setToolTip( 
"<b>" + tr( 
"Lock m coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + m for quick access" ) + 
")" );
 
  247  mRepeatingLockMButton->setToolTip( 
"<b>" + tr( 
"Continuously lock m coordinate" ) + 
"</b>" );
 
  258  mFloaterActionsMenu = 
new QMenu( 
this );
 
  259  qobject_cast< QToolButton *>( mToolbar->widgetForAction( mFloaterAction ) )->setPopupMode( QToolButton::InstantPopup );
 
  260  mFloaterAction->setMenu( mFloaterActionsMenu );
 
  261  mFloaterAction->setCheckable( 
true );
 
  263  mFloaterAction->setChecked( mFloater->
active() );
 
  267    QAction *action = 
new QAction( tr( 
"Show floater" ), mFloaterActionsMenu );
 
  268    action->setCheckable( 
true );
 
  269    action->setChecked( mFloater->
active() );
 
  270    mFloaterActionsMenu->addAction( action );
 
  271    connect( action, &QAction::toggled, 
this, [ = ]( 
bool checked )
 
  274      mFloaterAction->setChecked( checked );
 
  278  mFloaterActionsMenu->addSeparator();
 
  281    QAction *action = 
new QAction( tr( 
"Show distance" ), mFloaterActionsMenu );
 
  282    action->setCheckable( 
true );
 
  283    mFloaterActionsMenu->addAction( action );
 
  284    connect( action, &QAction::toggled, 
this, [ = ]( 
bool checked )
 
  288    action->setChecked( 
QgsSettings().value( QStringLiteral( 
"/Cad/DistanceShowInFloater" ), 
true ).toBool() );
 
  292    QAction *action = 
new QAction( tr( 
"Show angle" ), mFloaterActionsMenu );
 
  293    action->setCheckable( 
true );
 
  294    mFloaterActionsMenu->addAction( action );
 
  295    connect( action, &QAction::toggled, 
this, [ = ]( 
bool checked )
 
  299    action->setChecked( 
QgsSettings().value( QStringLiteral( 
"/Cad/AngleShowInFloater" ), 
true ).toBool() );
 
  303    QAction *action = 
new QAction( tr( 
"Show XY coordinates" ), mFloaterActionsMenu );
 
  304    action->setCheckable( 
true );
 
  305    mFloaterActionsMenu->addAction( action );
 
  306    connect( action, &QAction::toggled, 
this, [ = ]( 
bool checked )
 
  312    action->setChecked( 
QgsSettings().value( QStringLiteral( 
"/Cad/XCoordinateShowInFloater" ), 
true ).toBool() );
 
  316    QAction *action = 
new QAction( tr( 
"Show Z value" ), mFloaterActionsMenu );
 
  317    action->setCheckable( 
true );
 
  318    mFloaterActionsMenu->addAction( action );
 
  319    connect( action, &QAction::toggled, 
this, [ = ]( 
bool checked )
 
  323    action->setChecked( 
QgsSettings().value( QStringLiteral( 
"/Cad/ZCoordinateShowInFloater" ), 
true ).toBool() );
 
  327    QAction *action = 
new QAction( tr( 
"Show M value" ), mFloaterActionsMenu );
 
  328    action->setCheckable( 
true );
 
  329    mFloaterActionsMenu->addAction( action );
 
  330    connect( action, &QAction::toggled, 
this, [ = ]( 
bool checked )
 
  334    action->setChecked( 
QgsSettings().value( QStringLiteral( 
"/Cad/MCoordinateShowInFloater" ), 
true ).toBool() );
 
  338    QAction *action = 
new QAction( tr( 
"Show bearing/azimuth" ), mFloaterActionsMenu );
 
  339    action->setCheckable( 
true );
 
  340    mFloaterActionsMenu->addAction( action );
 
  341    connect( action, &QAction::toggled, 
this, [ = ]( 
bool checked )
 
  345    action->setChecked( 
QgsSettings().value( QStringLiteral( 
"/Cad/BearingShowInFloater" ), 
false ).toBool() );
 
  349    QAction *action = 
new QAction( tr( 
"Show common snapping angle" ), mFloaterActionsMenu );
 
  350    action->setCheckable( 
true );
 
  351    mFloaterActionsMenu->addAction( action );
 
  352    connect( action, &QAction::toggled, 
this, [ = ]( 
bool checked )
 
  356    action->setChecked( 
QgsSettings().value( QStringLiteral( 
"/Cad/CommonAngleSnappingShowInFloater" ), 
false ).toBool() );
 
  359  updateCapacity( 
true );
 
  368    return  tr( 
"Do Not Snap to Common Angles" );
 
  370    return QString( tr( 
"%1, %2, %3, %4°…" ) ).arg( 
angle, 0, 
'f', 1 ).arg( 
angle * 2, 0, 
'f', 1 ).arg( 
angle * 3, 0, 
'f', 1 ).arg( 
angle * 4, 0, 
'f', 1 );
 
  375  mXLineEdit->setText( value );
 
  376  if ( mode == WidgetSetMode::ReturnPressed )
 
  378    emit mXLineEdit->returnPressed();
 
  380  else if ( mode == WidgetSetMode::FocusOut )
 
  382    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  383    QCoreApplication::postEvent( mXLineEdit, e );
 
  385  else if ( mode == WidgetSetMode::TextEdited )
 
  387    emit mXLineEdit->textEdited( value );
 
  392  mYLineEdit->setText( value );
 
  393  if ( mode == WidgetSetMode::ReturnPressed )
 
  395    emit mYLineEdit->returnPressed();
 
  397  else if ( mode == WidgetSetMode::FocusOut )
 
  399    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  400    QCoreApplication::postEvent( mYLineEdit, e );
 
  402  else if ( mode == WidgetSetMode::TextEdited )
 
  404    emit mYLineEdit->textEdited( value );
 
  409  mZLineEdit->setText( value );
 
  410  if ( mode == WidgetSetMode::ReturnPressed )
 
  412    emit mZLineEdit->returnPressed();
 
  414  else if ( mode == WidgetSetMode::FocusOut )
 
  416    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  417    QCoreApplication::postEvent( mZLineEdit, e );
 
  419  else if ( mode == WidgetSetMode::TextEdited )
 
  421    emit mZLineEdit->textEdited( value );
 
  426  mMLineEdit->setText( value );
 
  427  if ( mode == WidgetSetMode::ReturnPressed )
 
  429    emit mMLineEdit->returnPressed();
 
  431  else if ( mode == WidgetSetMode::FocusOut )
 
  433    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  434    QCoreApplication::postEvent( mMLineEdit, e );
 
  436  else if ( mode == WidgetSetMode::TextEdited )
 
  438    emit mMLineEdit->textEdited( value );
 
  443  mAngleLineEdit->setText( value );
 
  444  if ( mode == WidgetSetMode::ReturnPressed )
 
  446    emit mAngleLineEdit->returnPressed();
 
  448  else if ( mode == WidgetSetMode::FocusOut )
 
  450    emit mAngleLineEdit->textEdited( value );
 
  455  mDistanceLineEdit->setText( value );
 
  456  if ( mode == WidgetSetMode::ReturnPressed )
 
  458    emit mDistanceLineEdit->returnPressed();
 
  460  else if ( mode == WidgetSetMode::FocusOut )
 
  462    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  463    QCoreApplication::postEvent( mDistanceLineEdit, e );
 
  465  else if ( mode == WidgetSetMode::TextEdited )
 
  467    emit mDistanceLineEdit->textEdited( value );
 
  472void QgsAdvancedDigitizingDockWidget::setCadEnabled( 
bool enabled )
 
  474  mCadEnabled = enabled;
 
  475  mEnableAction->setChecked( enabled );
 
  476  mConstructionModeAction->setEnabled( enabled );
 
  477  mSettingsAction->setEnabled( enabled );
 
  478  mInputWidgets->setEnabled( enabled );
 
  479  mFloaterAction->setEnabled( enabled );
 
  480  mConstructionAction->setEnabled( enabled );
 
  485    mLineExtensionAction->setChecked( 
false );
 
  486    mXyVertexAction->setChecked( 
false );
 
  488    mParallelAction->setEnabled( 
false );
 
  489    mPerpendicularAction->setEnabled( 
false );
 
  495  setConstructionMode( 
false );
 
  511  bool enableZ = 
false;
 
  512  bool enableM = 
false;
 
  516    switch ( layer->type() )
 
  518      case Qgis::LayerType::Vector:
 
  527      case Qgis::LayerType::Mesh:
 
  529        QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
 
  534      case Qgis::LayerType::Raster:
 
  535      case Qgis::LayerType::Plugin:
 
  536      case Qgis::LayerType::VectorTile:
 
  537      case Qgis::LayerType::Annotation:
 
  538      case Qgis::LayerType::PointCloud:
 
  539      case Qgis::LayerType::Group:
 
  550  mRelativeZButton->setEnabled( 
enable );
 
  551  mZLabel->setEnabled( 
enable );
 
  552  mZLineEdit->setEnabled( 
enable );
 
  553  if ( mZLineEdit->isEnabled() )
 
  557  mLockZButton->setEnabled( 
enable );
 
  563  mRelativeMButton->setEnabled( 
enable );
 
  564  mMLabel->setEnabled( 
enable );
 
  565  mMLineEdit->setEnabled( 
enable );
 
  566  if ( mMLineEdit->isEnabled() )
 
  570  mLockMButton->setEnabled( 
enable );
 
  574void QgsAdvancedDigitizingDockWidget::activateCad( 
bool enabled )
 
  576  enabled &= mCurrentMapToolSupportsCad;
 
  578  mSessionActive = enabled;
 
  580  if ( enabled && !isVisible() )
 
  585  setCadEnabled( enabled );
 
  588void QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked( 
bool activated )
 
  594  else if ( sender() == mParallelAction )
 
  598  else if ( sender() == mPerpendicularAction )
 
  604void QgsAdvancedDigitizingDockWidget::setConstraintRelative( 
bool activate )
 
  606  if ( sender() == mRelativeAngleButton )
 
  608    mAngleConstraint->setRelative( activate );
 
  611  else if ( sender() == mRelativeXButton )
 
  613    mXConstraint->setRelative( activate );
 
  616  else if ( sender() == mRelativeYButton )
 
  618    mYConstraint->setRelative( activate );
 
  621  else if ( sender() == mRelativeZButton )
 
  623    mZConstraint->setRelative( activate );
 
  626  else if ( sender() == mRelativeMButton )
 
  628    mMConstraint->setRelative( activate );
 
  633void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock( 
bool activate )
 
  635  if ( sender() == mRepeatingLockDistanceButton )
 
  637    mDistanceConstraint->setRepeatingLock( activate );
 
  639  else if ( sender() == mRepeatingLockAngleButton )
 
  641    mAngleConstraint->setRepeatingLock( activate );
 
  643  else if ( sender() == mRepeatingLockXButton )
 
  645    mXConstraint->setRepeatingLock( activate );
 
  647  else if ( sender() == mRepeatingLockYButton )
 
  649    mYConstraint->setRepeatingLock( activate );
 
  651  else if ( sender() == mRepeatingLockZButton )
 
  653    mZConstraint->setRepeatingLock( activate );
 
  655  else if ( sender() == mRepeatingLockMButton )
 
  657    mMConstraint->setRepeatingLock( activate );
 
  661void QgsAdvancedDigitizingDockWidget::setConstructionMode( 
bool enabled )
 
  663  mConstructionMode = enabled;
 
  664  mConstructionModeAction->setChecked( enabled );
 
  667void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
 
  670  const QMap<QAction *, double>::const_iterator ica = mCommonAngleActions.constFind( action );
 
  671  if ( ica != mCommonAngleActions.constEnd() )
 
  673    ica.key()->setChecked( 
true );
 
  674    mCommonAngleConstraint = ica.value();
 
  676    mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
 
  682QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
 const 
  686    return advancedTool->layer();
 
  700  if ( releaseRepeatingLocks )
 
  702    mXyVertexAction->setChecked( 
false );
 
  706    mLineExtensionAction->setChecked( 
false );
 
  713  if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
 
  718  if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
 
  723  if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
 
  728  if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
 
  733  if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
 
  738  if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
 
  744  if ( !mCadPointList.empty() )
 
  746    if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
 
  748      mXConstraint->setValue( mCadPointList.constLast().x(), 
true );
 
  750    if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
 
  752      mYConstraint->setValue( mCadPointList.constLast().y(), 
true );
 
  754    if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
 
  756      mZConstraint->setValue( mCadPointList.constLast().z(), 
true );
 
  758    if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
 
  760      mMConstraint->setValue( mCadPointList.constLast().m(), 
true );
 
  767void QgsAdvancedDigitizingDockWidget::emit pointChanged()
 
  770  QPoint globalPos = mMapCanvas->cursor().pos();
 
  771  QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
 
  772  QMouseEvent *e = 
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
 
  773  mCurrentMapTool->canvasMoveEvent( e );
 
  779  CadConstraint *constraint = 
nullptr;
 
  780  if ( obj == mAngleLineEdit || obj == mLockAngleButton )
 
  782    constraint = mAngleConstraint.get();
 
  784  else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
 
  786    constraint = mDistanceConstraint.get();
 
  788  else if ( obj == mXLineEdit  || obj == mLockXButton )
 
  790    constraint = mXConstraint.get();
 
  792  else if ( obj == mYLineEdit  || obj == mLockYButton )
 
  794    constraint = mYConstraint.get();
 
  796  else if ( obj == mZLineEdit  || obj == mLockZButton )
 
  798    constraint = mZConstraint.get();
 
  800  else if ( obj == mMLineEdit  || obj == mLockMButton )
 
  802    constraint = mMConstraint.get();
 
  804  else if ( obj == mLineExtensionAction )
 
  806    constraint = mLineExtensionConstraint.get();
 
  808  else if ( obj == mXyVertexAction )
 
  810    constraint = mXyVertexConstraint.get();
 
  815double QgsAdvancedDigitizingDockWidget::parseUserInput( 
const QString &inputValue, 
const Qgis::CadConstraintType type, 
bool &ok )
 const 
  819  QString cleanedInputValue { inputValue };
 
  823    cleanedInputValue.remove( tr( 
"°" ) );
 
  843        value *= factorUnits;
 
  859    const QVariant result = expr.evaluate();
 
  860    if ( expr.hasEvalError() )
 
  863      QString inputValueC { inputValue };
 
  866      if ( inputValue.contains( QLocale().groupSeparator() ) )
 
  868        inputValueC.remove( QLocale().groupSeparator() );
 
  870        const QVariant resultC = exprC.evaluate();
 
  871        if ( ! exprC.hasEvalError() )
 
  873          value = resultC.toDouble( &ok );
 
  878      if ( !ok && QLocale().decimalPoint() != QChar( 
'.' ) && inputValueC.contains( QLocale().decimalPoint() ) )
 
  880        QgsExpression exprC( inputValueC .replace( QLocale().decimalPoint(), QChar( 
'.' ) ) );
 
  881        const QVariant resultC = exprC.evaluate();
 
  882        if ( ! exprC.hasEvalError() )
 
  884          value = resultC.toDouble( &ok );
 
  890      value = result.toDouble( &ok );
 
  896void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint, 
const QString &textValue, 
bool convertExpression )
 
  898  if ( !constraint || textValue.isEmpty() )
 
  907  const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
 
  911  constraint->setValue( value, convertExpression );
 
  916void QgsAdvancedDigitizingDockWidget::lockConstraint( 
bool activate  )
 
  918  CadConstraint *constraint = objectToConstraint( sender() );
 
  926    const QString textValue = constraint->lineEdit()->text();
 
  927    if ( !textValue.isEmpty() )
 
  930      const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
 
  933        constraint->setValue( value );
 
  947  if ( constraint == mXConstraint.get() )
 
  951  else if ( constraint == mYConstraint.get() )
 
  955  else if ( constraint == mZConstraint.get() )
 
  959  else if ( constraint == mMConstraint.get() )
 
  963  else if ( constraint == mDistanceConstraint.get() )
 
  967  else if ( constraint == mAngleConstraint.get() )
 
  975    if ( constraint == mAngleConstraint.get() )
 
  985void QgsAdvancedDigitizingDockWidget::constraintTextEdited( 
const QString &textValue )
 
  987  CadConstraint *constraint = objectToConstraint( sender() );
 
  993  updateConstraintValue( constraint, textValue, 
false );
 
  996void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
 
  998  QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
 
 1002  CadConstraint *constraint = objectToConstraint( lineEdit );
 
 1008  updateConstraintValue( constraint, lineEdit->text(), 
true );
 
 1013  mBetweenLineConstraint = constraint;
 
 1018void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint( 
bool activate  )
 
 1020  CadConstraint *constraint = objectToConstraint( sender() );
 
 1028  if ( constraint == mXyVertexConstraint.get() )
 
 1032  else if ( constraint == mLineExtensionConstraint.get() )
 
 1046void QgsAdvancedDigitizingDockWidget::updateCapacity( 
bool updateUIwithoutChange )
 
 1048  CadCapacities newCapacities = CadCapacities();
 
 1052  if ( mCadPointList.count() > 1 )
 
 1055    if ( !isGeographic )
 
 1061  if ( mCadPointList.count() > 2 )
 
 1063    if ( !isGeographic )
 
 1066  if ( !updateUIwithoutChange && newCapacities == mCapacities )
 
 1076  const bool distance =  mCadEnabled && newCapacities.testFlag( 
Distance );
 
 1077  const bool relativeAngle = mCadEnabled && newCapacities.testFlag( 
RelativeAngle );
 
 1078  const bool absoluteAngle = mCadEnabled && newCapacities.testFlag( 
AbsoluteAngle );
 
 1079  const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag( 
RelativeCoordinates );
 
 1081  mPerpendicularAction->setEnabled( distance && snappingEnabled );
 
 1082  mParallelAction->setEnabled( distance && snappingEnabled );
 
 1084  mLineExtensionAction->setEnabled( snappingEnabled );
 
 1085  mXyVertexAction->setEnabled( snappingEnabled );
 
 1089  if ( !snappingEnabled )
 
 1091    mPerpendicularAction->setToolTip( tr( 
"Snapping must be enabled to utilize perpendicular mode." ) );
 
 1092    mParallelAction->setToolTip( tr( 
"Snapping must be enabled to utilize parallel mode." ) );
 
 1093    mLineExtensionAction->setToolTip( tr( 
"Snapping must be enabled to utilize line extension mode." ) );
 
 1094    mXyVertexAction->setToolTip( tr( 
"Snapping must be enabled to utilize xy point mode." ) );
 
 1096  else if ( mCadPointList.count() <= 1 )
 
 1098    mPerpendicularAction->setToolTip( tr( 
"A first vertex should be drawn to utilize perpendicular mode." ) );
 
 1099    mParallelAction->setToolTip( tr( 
"A first vertex should be drawn to utilize parallel mode." ) );
 
 1101  else if ( isGeographic )
 
 1103    mPerpendicularAction->setToolTip( tr( 
"Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 1104    mParallelAction->setToolTip( tr( 
"Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 1108    mPerpendicularAction->setToolTip( 
"<b>" + tr( 
"Perpendicular" ) + 
"</b><br>(" + tr( 
"press p to switch between perpendicular, parallel and normal mode" ) + 
")" );
 
 1109    mParallelAction->setToolTip( 
"<b>" + tr( 
"Parallel" ) + 
"</b><br>(" + tr( 
"press p to switch between perpendicular, parallel and normal mode" ) + 
")" );
 
 1113  if ( !absoluteAngle )
 
 1119  mLockAngleButton->setEnabled( absoluteAngle );
 
 1120  mRelativeAngleButton->setEnabled( relativeAngle );
 
 1121  mAngleLineEdit->setEnabled( absoluteAngle );
 
 1123  if ( !absoluteAngle )
 
 1127  if ( !relativeAngle )
 
 1129    mAngleConstraint->setRelative( 
false );
 
 1132  else if ( relativeAngle && !mCapacities.testFlag( 
RelativeAngle ) )
 
 1135    mAngleConstraint->setRelative( 
true );
 
 1140  mLockDistanceButton->setEnabled( distance && relativeCoordinates );
 
 1141  mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
 
 1143  if ( !( distance && relativeCoordinates ) )
 
 1148  mRelativeXButton->setEnabled( relativeCoordinates );
 
 1149  mRelativeYButton->setEnabled( relativeCoordinates );
 
 1150  mRelativeZButton->setEnabled( relativeCoordinates );
 
 1151  mRelativeMButton->setEnabled( relativeCoordinates );
 
 1154  mCapacities = newCapacities;
 
 1162  constr.
locked = 
c->isLocked();
 
 1164  constr.
value = 
c->value();
 
 1171  if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
 
 1177  const int lastIndex = mLockedSnapVertices.length() - 1;
 
 1178  for ( 
int i = lastIndex ; i >= 0; --i )
 
 1180    if ( mLockedSnapVertices[i].point() == snapMatch.
point() )
 
 1182      if ( snapMatch.
point() != previouslySnap.
point() )
 
 1184        mLockedSnapVertices.removeAt( i );
 
 1190  if ( snapMatch.
point() != previouslySnap.
point() )
 
 1192    mLockedSnapVertices.enqueue( snapMatch );
 
 1195  if ( mLockedSnapVertices.count() > 3 )
 
 1197    mLockedSnapVertices.dequeue();
 
 1206  context.
xConstraint = _constraint( mXConstraint.get() );
 
 1207  context.
yConstraint = _constraint( mYConstraint.get() );
 
 1208  context.
zConstraint = _constraint( mZConstraint.get() );
 
 1209  context.
mConstraint = _constraint( mMConstraint.get() );
 
 1226  const bool res = output.
valid;
 
 1228  mSnappedSegment.clear();
 
 1233    mSnappedSegment << edgePt0 << edgePt1;
 
 1254    mSnapIndicator->setMatch( output.
snapMatch );
 
 1255    mSnapIndicator->setVisible( 
true );
 
 1259    mSnapIndicator->setVisible( 
false );
 
 1280  if ( mSnapMatch.
layer() )
 
 1292    toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
 
 1293    mLastSnapMatch = mSnapMatch;
 
 1303  if ( mLockZButton->isChecked() )
 
 1305    point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
 
 1307  if ( mLockMButton->isChecked() )
 
 1309    point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
 
 1315  updateUnlockedConstraintValues( point );
 
 1323    emit 
pushWarning( tr( 
"Some constraints are incompatible. Resulting point might be incorrect." ) );
 
 1330void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues( 
const QgsPoint &point )
 
 1332  bool previousPointExist, penulPointExist;
 
 1337  if ( !mAngleConstraint->isLocked() && previousPointExist )
 
 1339    double prevAngle = 0.0;
 
 1341    if ( penulPointExist && mAngleConstraint->relative() )
 
 1344      prevAngle = std::atan2( previousPt.
y() - penultimatePt.
y(),
 
 1345                              previousPt.
x() - penultimatePt.
x() )  * 180 / M_PI;
 
 1348    const double xAngle { std::atan2( point.
y() - previousPt.
y(),
 
 1349                                      point.
x() - previousPt.
x() ) * 180 / M_PI };
 
 1352    const double angle = std::fmod( xAngle - prevAngle, 360.0 );
 
 1353    mAngleConstraint->setValue( 
angle );
 
 1356    double bearing { std::fmod( xAngle, 360.0 ) };
 
 1357    bearing = bearing <= 90.0 ? 90.0 - bearing : ( bearing > 90 ? 270.0 + 180.0 - bearing : 270.0 - bearing );
 
 1364  if ( !mDistanceConstraint->isLocked() && previousPointExist )
 
 1366    mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
 
 1369  if ( !mXConstraint->isLocked() )
 
 1371    if ( previousPointExist && mXConstraint->relative() )
 
 1373      mXConstraint->setValue( point.
x() - previousPt.
x() );
 
 1377      mXConstraint->setValue( point.
x() );
 
 1381  if ( !mYConstraint->isLocked() )
 
 1383    if ( previousPointExist && mYConstraint->relative() )
 
 1385      mYConstraint->setValue( point.
y() - previousPt.
y() );
 
 1389      mYConstraint->setValue( point.
y() );
 
 1393  if ( !mZConstraint->isLocked() )
 
 1395    if ( previousPointExist && mZConstraint->relative() )
 
 1397      mZConstraint->setValue( point.
z() - previousPt.
z() );
 
 1401      mZConstraint->setValue( point.
z() );
 
 1405  if ( !mMConstraint->isLocked() )
 
 1407    if ( previousPointExist && mMConstraint->relative() )
 
 1409      mMConstraint->setValue( point.
m() - previousPt.
m() );
 
 1413      mMConstraint->setValue( point.
m() );
 
 1419QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers( 
const QgsPointXY &originalMapPoint, 
bool *snapped )
 const 
 1431  localConfig.
setTypeFlag( Qgis::SnappingType::Segment );
 
 1432  snappingUtils->
setConfig( localConfig );
 
 1434  match = snappingUtils->
snapToMap( originalMapPoint, 
nullptr, 
true );
 
 1436  snappingUtils->
setConfig( canvasConfig );
 
 1446    *snapped = 
segment.count() == 2;
 
 1459  bool previousPointExist, penulPointExist, snappedSegmentExist;
 
 1462  mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
 
 1464  if ( !previousPointExist || !snappedSegmentExist )
 
 1469  double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
 
 1471  if ( mAngleConstraint->relative() && penulPointExist )
 
 1473    angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
 
 1481  angle *= 180 / M_PI;
 
 1483  mAngleConstraint->setValue( 
angle );
 
 1484  mAngleConstraint->setLockMode( lockMode );
 
 1502    case Qt::Key_Backspace:
 
 1503    case Qt::Key_Delete:
 
 1509    case Qt::Key_Escape:
 
 1539    case Qt::Key_Backspace:
 
 1540    case Qt::Key_Delete:
 
 1546    case Qt::Key_Escape:
 
 1553      filterKeyPress( e );
 
 1562  const auto constPoints = points;
 
 1569bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
 
 1573    return QgsDockWidget::eventFilter( obj, event );
 
 1581  if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
 
 1583    if ( QKeyEvent *keyEvent = 
dynamic_cast<QKeyEvent *
>( event ) )
 
 1585      return filterKeyPress( keyEvent );
 
 1588  return QgsDockWidget::eventFilter( obj, event );
 
 1591bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
 
 1597  const QEvent::Type type = e->type();
 
 1603      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1605        mXConstraint->toggleLocked();
 
 1610      else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
 1614          mXConstraint->toggleRelative();
 
 1621      else if ( type == QEvent::KeyPress )
 
 1623        mXLineEdit->setFocus();
 
 1624        mXLineEdit->selectAll();
 
 1633      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1635        mYConstraint->toggleLocked();
 
 1640      else if ( type == QEvent::ShortcutOverride &&  e->modifiers() == Qt::ShiftModifier )
 
 1644          mYConstraint->toggleRelative();
 
 1651      else if ( type == QEvent::KeyPress )
 
 1653        mYLineEdit->setFocus();
 
 1654        mYLineEdit->selectAll();
 
 1663      if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
 
 1665        mZConstraint->toggleLocked();
 
 1670      else if ( type == QEvent::ShortcutOverride &&  e->modifiers() == Qt::ShiftModifier )
 
 1674          mZConstraint->toggleRelative();
 
 1681      else if ( type == QEvent::KeyPress )
 
 1683        mZLineEdit->setFocus();
 
 1684        mZLineEdit->selectAll();
 
 1693      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1695        mMConstraint->toggleLocked();
 
 1700      else if ( type == QEvent::ShortcutOverride &&  e->modifiers() == Qt::ShiftModifier )
 
 1704          mMConstraint->toggleRelative();
 
 1711      else if ( type == QEvent::KeyPress )
 
 1713        mMLineEdit->setFocus();
 
 1714        mMLineEdit->selectAll();
 
 1723      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1727          mAngleConstraint->toggleLocked();
 
 1733      else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
 1737          mAngleConstraint->toggleRelative();
 
 1744      else if ( type == QEvent::KeyPress )
 
 1746        mAngleLineEdit->setFocus();
 
 1747        mAngleLineEdit->selectAll();
 
 1756      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1760          mDistanceConstraint->toggleLocked();
 
 1767      else if ( type == QEvent::KeyPress )
 
 1769        mDistanceLineEdit->setFocus();
 
 1770        mDistanceLineEdit->selectAll();
 
 1778      if ( type == QEvent::KeyPress )
 
 1780        setConstructionMode( !mConstructionMode );
 
 1787      if ( type == QEvent::KeyPress )
 
 1789        const bool parallel = mParallelAction->isChecked();
 
 1790        const bool perpendicular = mPerpendicularAction->isChecked();
 
 1792        if ( !parallel && !perpendicular )
 
 1796        else if ( perpendicular )
 
 1813      if ( type == QEvent::ShortcutOverride )
 
 1815        const QList<double> constActionValues { mCommonAngleActions.values() };
 
 1816        const int currentAngleActionIndex { 
static_cast<int>( constActionValues.indexOf( mCommonAngleConstraint ) ) };
 
 1817        const QList<QAction *> constActions { mCommonAngleActions.keys( ) };
 
 1818        QAction *nextAngleAction;
 
 1819        if ( e->modifiers() == Qt::ShiftModifier )
 
 1821          nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
 
 1825          nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
 
 1827        nextAngleAction->trigger();
 
 1837  return e->isAccepted();
 
 1846    mAngleLineEdit->setToolTip( tr( 
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 1847    mDistanceLineEdit->setToolTip( tr( 
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 1849    mLabelX->setText( tr( 
"Long" ) );
 
 1850    mLabelY->setText( tr( 
"Lat" ) );
 
 1852    mXConstraint->setPrecision( 8 );
 
 1853    mYConstraint->setPrecision( 8 );
 
 1857    mAngleLineEdit->setToolTip( 
"<b>" + tr( 
"Angle" ) + 
"</b><br>(" + tr( 
"press a for quick access" ) + 
")" );
 
 1858    mAngleLineEdit->setToolTip( QString() );
 
 1860    mDistanceLineEdit->setToolTip( 
"<b>" + tr( 
"Distance" ) + 
"</b><br>(" + tr( 
"press d for quick access" ) + 
")" );
 
 1862    mLabelX->setText( tr( 
"x" ) );
 
 1863    mLabelY->setText( tr( 
"y" ) );
 
 1865    mXConstraint->setPrecision( 6 );
 
 1866    mYConstraint->setPrecision( 6 );
 
 1871  mEnableAction->setEnabled( 
true );
 
 1872  mErrorLabel->hide();
 
 1875  mCurrentMapToolSupportsCad = 
true;
 
 1877  if ( mSessionActive && !isVisible() )
 
 1881  setCadEnabled( mSessionActive );
 
 1888  mEnableAction->setEnabled( 
false );
 
 1889  mErrorLabel->setText( tr( 
"CAD tools are not enabled for the current map tool" ) );
 
 1890  mErrorLabel->show();
 
 1893  mCurrentMapToolSupportsCad = 
false;
 
 1895  mSnapIndicator->setVisible( 
false );
 
 1897  setCadEnabled( 
false );
 
 1902  mCadPaintItem->update();
 
 1907  if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
 
 1912  mLockedSnapVertices.clear();
 
 1918  QgsPoint pt = pointXYToPoint( point );
 
 1921    mCadPointList << pt;
 
 1925    mCadPointList.insert( 0, pt );
 
 1938  mCadPointList.removeAt( i );
 
 1945  mCadPointList.clear();
 
 1946  mSnappedSegment.clear();
 
 1956    mCadPointList << point;
 
 1961    mCadPointList[0] = point;
 
 1969  mLockerButton->setChecked( mode == 
HardLock );
 
 1970  if ( mRepeatingLockButton )
 
 1974      mRepeatingLockButton->setEnabled( 
true );
 
 1978      mRepeatingLockButton->setChecked( 
false );
 
 1979      mRepeatingLockButton->setEnabled( 
false );
 
 1992  mRepeatingLock = repeating;
 
 1993  if ( mRepeatingLockButton )
 
 1994    mRepeatingLockButton->setChecked( repeating );
 
 1999  mRelative = relative;
 
 2000  if ( mRelativeButton )
 
 2002    mRelativeButton->setChecked( relative );
 
 2009  if ( updateWidget && mLineEdit->isEnabled() )
 
 2010    mLineEdit->setText( displayValue() );
 
 2015  switch ( mCadConstraintType )
 
 2019      return QLocale().toString( mValue, 
'f', mPrecision ).append( tr( 
" °" ) );
 
 2026        return QLocale().toString( mValue, 
'f', mPrecision ).append( tr( 
" °" ) );
 
 2030        return QLocale().toString( mValue, 
'f', mPrecision );
 
 2038      const double convertedValue { mValue * factorUnits };
 
 2047  return QLocale().toString( mValue, 
'f', mPrecision );
 
 2052  setLockMode( mLockMode == HardLock ? NoLock : HardLock );
 
 2057  setRelative( !mRelative );
 
 2063  if ( mLineEdit->isEnabled() )
 
 2064    mLineEdit->setText( displayValue() );
 
 2069  return mCadConstraintType;
 
 2074  mCadConstraintType = constraintType;
 
 2079  mMapCanvas = mapCanvas;
 
 2087    return mCadPointList.value( 0 );
 
 2096    QgsPoint res = mCadPointList.value( 0 );
 
 2098    res.
setX( layerCoordinates.
x() );
 
 2099    res.
setY( layerCoordinates.
y() );
 
 2110    return mCadPointList.value( 1 );
 
 2120    return mCadPointList.value( 2 );
 
 2125QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint( 
const QgsPointXY &point )
 const 
 2132  return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
 
 2137  return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
 
DistanceUnit
Units of distance.
 
CadConstraintType
Advanced digitizing constraint type.
 
@ Distance
Distance value.
 
@ YCoordinate
Y Coordinate value.
 
@ XCoordinate
X Coordinate value.
 
@ AllLayers
On all vector layers.
 
BetweenLineConstraint
Between line constraints which can be enabled.
 
@ NoConstraint
No additional constraint.
 
@ Perpendicular
Perpendicular.
 
WkbType
The WKB type describes the number of dimensions a geometry has.
 
The QgsAdvancedDigitizingCanvasItem class draws the graphical elements of the CAD tools (.
 
void updatePosition() override
called on changed extent or resize event to update position of the item
 
The QgsAdvancedDigitizingFloater class is widget that floats next to the mouse pointer,...
 
void setItemVisibility(const QgsAdvancedDigitizingFloater::FloaterItem &item, bool visible)
Set whether the floater item should be visible or not.
 
void setActive(bool active)
Set whether the floater should be active or not.
 
bool active()
Whether the floater is active or not.
 
Structure with details of one constraint.
 
bool locked
Whether the constraint is active, i.e. should be considered.
 
double value
Numeric value of the constraint (coordinate/distance in map units or angle in degrees)
 
bool relative
Whether the value is relative to previous value.
 
Defines constraints for the QgsCadUtils::alignMapPoint() method.
 
QgsCadUtils::AlignMapPointConstraint xyVertexConstraint
 
QgsCadUtils::AlignMapPointConstraint yConstraint
Constraint for Y coordinate.
 
QgsCadUtils::AlignMapPointConstraint xConstraint
Constraint for X coordinate.
 
double mapUnitsPerPixel
Map units/pixel ratio from map canvas.
 
void setCadPoints(const QList< QgsPoint > &points)
Sets the list of recent CAD points (in map coordinates).
 
void setLockedSnapVertices(const QQueue< QgsPointLocator::Match > &lockedSnapVertices)
Sets the queue of locked vertices.
 
QgsCadUtils::AlignMapPointConstraint mConstraint
Constraint for M coordinate.
 
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
 
bool snappingToFeaturesOverridesCommonAngle
Flag to set snapping to features priority over common angle.
 
QgsCadUtils::AlignMapPointConstraint zConstraint
Constraint for Z coordinate.
 
QgsSnappingUtils * snappingUtils
Snapping utils that will be used to snap point to map. Must not be nullptr.
 
QgsCadUtils::AlignMapPointConstraint commonAngleConstraint
Constraint for soft lock to a common angle.
 
QgsCadUtils::AlignMapPointConstraint lineExtensionConstraint
 
QgsCadUtils::AlignMapPointConstraint angleConstraint
Constraint for angle.
 
Structure returned from alignMapPoint() method.
 
Qgis::LineExtensionSide softLockLineExtension
 
QgsPointXY finalMapPoint
map point aligned according to the constraints
 
bool valid
Whether the combination of constraints is actually valid.
 
QgsPointLocator::Match snapMatch
Snapped point - only valid if actually used for something.
 
double softLockCommonAngle
Angle (in degrees) to which we have soft-locked ourselves (if not set it is -1)
 
static QgsCadUtils::AlignMapPointOutput alignMapPoint(const QgsPointXY &originalMapPoint, const QgsCadUtils::AlignMapPointContext &ctx)
Applies X/Y/angle/distance constraints from the given context to a map point.
 
static QString formatDistance(double distance, int decimals, Qgis::DistanceUnit unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
 
Class for parsing and evaluation of expressions (formerly called "search strings").
 
A event filter for watching for focus events on a parent object.
 
void focusOut()
Emitted when parent object loses focus.
 
Map canvas is a class for displaying all GIS data types on a canvas.
 
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
 
void destinationCrsChanged()
Emitted when map CRS has changed.
 
QgsMapTool * mapTool()
Returns the currently active tool.
 
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
 
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
 
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
 
Base class for all map layer types.
 
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
 
QgsPointXY originalMapPoint() const
Returns the original, unmodified map point of the mouse cursor.
 
void setMapPoint(const QgsPointXY &point)
Set the (snapped) point this event points to in map coordinates.
 
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
 
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
 
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
 
Represents a mesh layer supporting display of data on structured or unstructured meshes.
 
bool isEditable() const override
Returns true if the layer can be edited.
 
A context for numeric formats.
 
A class to represent a 2D point.
 
Point geometry type, with support for z-dimension and m-values.
 
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
 
void setY(double y) SIP_HOLDGIL
Sets the point's y-coordinate.
 
void setZ(double z) SIP_HOLDGIL
Sets the point's z-coordinate.
 
double distanceSquared(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
 
void setM(double m) SIP_HOLDGIL
Sets the point's m-value.
 
const QgsBearingNumericFormat * bearingFormat() const
Returns the project bearing's format, which controls how bearings associated with the project are dis...
 
Qgis::DistanceUnit distanceUnits
 
static QgsProject * instance()
Returns the QgsProject singleton instance.
 
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
 
QgsSnappingConfig snappingConfig
 
QgsProjectDisplaySettings * displaySettings
 
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
 
bool setValue(const T &value, const QString &dynamicKeyPart=QString()) const
Set settings value.
 
A boolean settings entry.
 
static QgsSettingsTreeNode * sTreeDigitizing
 
This class is a composition of two QSettings instances:
 
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
 
Class that shows snapping marker on map canvas for the current snapping match.
 
This is a container for configuration of the snapping of the project.
 
void setTypeFlag(Qgis::SnappingTypes type)
define the type of snapping
 
void setMode(Qgis::SnappingMode mode)
define the mode of snapping
 
bool enabled() const
Returns if snapping is enabled.
 
This class has all the configuration of snapping and can return answers to snapping queries.
 
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
 
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
 
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
 
static Q_INVOKABLE QString toAbbreviatedString(Qgis::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
 
Represents a vector layer which manages a vector based data sets.
 
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
 
static bool hasZ(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
 
static bool hasM(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
 
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
 
QLineF segment(int index, QRectF rect, double radius)
 
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
 
QgsPoint interpolatedPoint(const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem()) const
Convenient method to return a point on an edge with linear interpolation of the Z value.
 
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
 
bool hasEdge() const
Returns true if the Match is an edge.
 
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
 
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
 
bool hasVertex() const
Returns true if the Match is a vertex.