Salome HOME
Bug #1596: Export does not work
[modules/shaper.git] / src / PartSet / PartSet_SketcherMgr.cpp
index 236124f63403168fd4daa1802849363696ff6d4b..29ff74c11f1366e531e570438be11aaede711783 100755 (executable)
@@ -12,6 +12,7 @@
 #include "PartSet_Tools.h"
 #include "PartSet_WidgetSketchLabel.h"
 #include "PartSet_WidgetEditor.h"
+#include "PartSet_ResultSketchPrs.h"
 
 #include <XGUI_ModuleConnector.h>
 #include <XGUI_Displayer.h>
@@ -35,6 +36,9 @@
 #include <ModuleBase_OperationFeature.h>
 #include <ModuleBase_Operation.h>
 #include <ModuleBase_WidgetEditor.h>
+#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_Tools.h>
+#include <ModuleBase_ResultPrs.h>
 
 #include <GeomDataAPI_Point2D.h>
 
 #include <ModelAPI_Session.h>
 #include <ModelAPI_AttributeString.h>
 
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_Tools.h>
+
 #include <QMouseEvent>
 #include <QApplication>
 #include <QCursor>
 #include <QMessageBox>
+#include <QMainWindow>
 
 //#define DEBUG_DO_NOT_BY_ENTER
 
 //#define DEBUG_CURSOR
 
 /// Returns list of unique objects by sum of objects from List1 and List2
-/*QList<ModuleBase_ViewerPrs> getSumList(const QList<ModuleBase_ViewerPrs>& theList1,
-                                       const QList<ModuleBase_ViewerPrs>& theList2)
+/*QList<ModuleBase_ViewerPrsPtr> getSumList(const QList<ModuleBase_ViewerPrsPtr>& theList1,
+                                       const QList<ModuleBase_ViewerPrsPtr>& theList2)
 {
-  QList<ModuleBase_ViewerPrs> aRes;
-  foreach (ModuleBase_ViewerPrs aPrs, theList1) {
+  QList<ModuleBase_ViewerPrsPtr> aRes;
+  foreach (ModuleBase_ViewerPrsPtr aPrs, theList1) {
     if (!aRes.contains(aPrs))
       aRes.append(aPrs);
   }
-  foreach (ModuleBase_ViewerPrs aPrs, theList2) {
+  foreach (ModuleBase_ViewerPrsPtr aPrs, theList2) {
     if (!aRes.contains(aPrs))
       aRes.append(aPrs);
   }
 // \param theSketch a sketch to project a vertex shape of a presentation to the plane
 // and find the corresponded attribute
 // \param theFeatureList  an output list of features
-void fillFeatureList(const QList<ModuleBase_ViewerPrs>& theList,
+void fillFeatureList(const QList<ModuleBase_ViewerPrsPtr>& theList,
                      const FeaturePtr theSketch,
                      QList<FeaturePtr>& theFeatureList)
 {
-  QList<ModuleBase_ViewerPrs> aRes;
+  QList<ModuleBase_ViewerPrsPtr> aRes;
 
-  QList<ModuleBase_ViewerPrs>::const_iterator anIt = theList.begin(),
+  QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = theList.begin(),
                                               aLast = theList.end();
   for (; anIt != aLast; anIt++)
   {
-    ModuleBase_ViewerPrs aPrs = *anIt;
-    FeaturePtr aFeature = ModelAPI_Feature::feature(aPrs.object());
+    ModuleBase_ViewerPrsPtr aPrs = *anIt;
+    FeaturePtr aFeature = ModelAPI_Feature::feature(aPrs->object());
     if (aFeature.get()  && !theFeatureList.contains(aFeature))
       theFeatureList.append(aFeature);
   }
@@ -189,6 +197,7 @@ PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
 
   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
+  myIsConstraintsShown[PartSet_Tools::Expressions] = false;
 }
 
 PartSet_SketcherMgr::~PartSet_SketcherMgr()
@@ -244,9 +253,6 @@ void PartSet_SketcherMgr::onLeaveViewPort()
 {
   myIsMouseOverViewProcessed = false;
   myIsMouseOverWindow = false;
-  // it is important to validate operation here only if sketch entity create operation is active
-  // because at this operation we reacts to the mouse leave/enter view port
-  //operationMgr()->onValidateOperation();
 
   #ifdef DEBUG_DO_NOT_BY_ENTER
   return;
@@ -267,6 +273,8 @@ void PartSet_SketcherMgr::onLeaveViewPort()
   if (myIsPopupMenuActive)
     return;
 
+  // it is important to validate operation here only if sketch entity create operation is active
+  // because at this operation we reacts to the mouse leave/enter view port
   operationMgr()->onValidateOperation();
 
   // 2. if the mouse IS NOT over window, reset the active widget value and hide the presentation
@@ -381,10 +389,6 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       return;
 
     Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
-    if (!aContext.IsNull()) {
-      // MoveTo in order to highlight current object
-      aContext->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
-    }
     // Remember highlighted objects for editing
     ModuleBase_ISelection* aSelect = aWorkshop->selection();
 
@@ -429,13 +433,8 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
 
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
 
-      // this is temporary commented in order to avoid the following wrong case:
-      // Distance constraint is under edition, double click on the digit -> nothing happens
-      // because QApplication::processEvents() calls onMouseDoubleClick, which try to show editor
-      // but as the prev edit is commited an new one is not started, editor is not shown.
-      // This is necessary in order to finalize previous operation
-      //QApplication::processEvents();
       launchEditing();
+      restoreSelection();
     }
   }
 }
@@ -611,8 +610,8 @@ void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMo
       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
       // Find corresponded widget to activate value editing
       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
-        if (aWgt->attributeID() == "ConstraintValue" ||
-            aWgt->attributeID() == "AngleValue") {
+        if (aWgt->attributeID() == SketchPlugin_Constraint::VALUE() ||
+            aWgt->attributeID() == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()) {
           PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
           if (anEditor)
             anEditor->showPopupEditor();
@@ -694,7 +693,7 @@ void PartSet_SketcherMgr::launchEditing()
     FeaturePtr aFeature = myCurrentSelection.begin().key();
     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
-    if (aSPFeature) {
+    if (aSPFeature && (!aSPFeature->isExternal())) {
       myModule->editFeature(aSPFeature);
     }
   }
@@ -713,16 +712,17 @@ bool PartSet_SketcherMgr::sketchSolverError()
 
 QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
 {
-  QString anError = "";
+  std::string anError = "";
   if (!theFeature.get() || !theFeature->data()->isValid())
-    return anError;
+    return anError.c_str();
 
   CompositeFeaturePtr aSketch = activeSketch();
   if (aSketch.get() && aSketch == theFeature) {
     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
-    anError = aAttributeString->value().c_str();
+    anError = aAttributeString->value();
+    ModuleBase_Tools::translate(aSketch->getKind(), anError);
   }
-  return anError;
+  return anError.c_str();
 }
 
 void PartSet_SketcherMgr::clearClickedFlags()
@@ -744,34 +744,43 @@ const QStringList& PartSet_SketcherMgr::sketchOperationIdList()
     // TODO
     // SketchRectangle is a python feature, so its ID is passed just as a string
     aIds << "SketchRectangle";
+    aIds.append(replicationsIdList());
     aIds.append(constraintsIdList());
   }
   return aIds;
 }
 
+const QStringList& PartSet_SketcherMgr::replicationsIdList()
+{
+  static QStringList aReplicationIds;
+  if (aReplicationIds.size() == 0) {
+    aReplicationIds << SketchPlugin_ConstraintMirror::ID().c_str();
+    aReplicationIds << SketchPlugin_MultiRotation::ID().c_str();
+    aReplicationIds << SketchPlugin_MultiTranslation::ID().c_str();
+  }
+  return aReplicationIds;
+}
+
 const QStringList& PartSet_SketcherMgr::constraintsIdList()
 {
-  static QStringList aIds;
-  if (aIds.size() == 0) {
-    aIds << SketchPlugin_ConstraintLength::ID().c_str();
-    aIds << SketchPlugin_ConstraintDistance::ID().c_str();
-    aIds << SketchPlugin_ConstraintRigid::ID().c_str();
-    aIds << SketchPlugin_ConstraintRadius::ID().c_str();
-    aIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
-    aIds << SketchPlugin_ConstraintParallel::ID().c_str();
-    aIds << SketchPlugin_ConstraintHorizontal::ID().c_str();
-    aIds << SketchPlugin_ConstraintVertical::ID().c_str();
-    aIds << SketchPlugin_ConstraintEqual::ID().c_str();
-    aIds << SketchPlugin_ConstraintTangent::ID().c_str();
-    aIds << SketchPlugin_ConstraintCoincidence::ID().c_str();
-    aIds << SketchPlugin_ConstraintMirror::ID().c_str();
-    aIds << SketchPlugin_ConstraintAngle::ID().c_str();
-    aIds << SketchPlugin_MultiRotation::ID().c_str();
-    aIds << SketchPlugin_MultiTranslation::ID().c_str();
-    aIds << SketchPlugin_ConstraintCollinear::ID().c_str();
-    aIds << SketchPlugin_ConstraintMiddle::ID().c_str();
+  static QStringList aConstraintIds;
+  if (aConstraintIds.size() == 0) {
+    aConstraintIds << SketchPlugin_ConstraintLength::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintDistance::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintRigid::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintRadius::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintParallel::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintHorizontal::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintVertical::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintEqual::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintTangent::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintCoincidence::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintAngle::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintCollinear::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintMiddle::ID().c_str();
   }
-  return aIds;
+  return aConstraintIds;
 }
 
 void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)
@@ -785,6 +794,17 @@ void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)
   theModes.append(TopAbs_EDGE);
 }
 
+Handle(AIS_InteractiveObject) PartSet_SketcherMgr::createPresentation(const ResultPtr& theResult)
+{
+  Handle(AIS_InteractiveObject) aPrs;
+
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
+  if (aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID()) {
+    aPrs = new PartSet_ResultSketchPrs(theResult);
+  }
+  return aPrs;
+}
+
 bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)
 {
   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();
@@ -845,7 +865,6 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   // Display all sketcher sub-Objects
   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
-  aConnector->workshop()->displayer()->activateTrihedron(true);
 
   // Hide sketcher result
   std::list<ResultPtr> aResults = myCurrentSketch->results();
@@ -855,6 +874,40 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   }
   myCurrentSketch->setDisplayed(false);
 
+  // Remove invalid sketch entities
+  std::set<FeaturePtr> anInvalidFeatures;
+  ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
+  for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
+    FeaturePtr aFeature = myCurrentSketch->subFeature(i);
+    if (aFeature.get()) {
+      if (!aFactory->validate(aFeature))
+        anInvalidFeatures.insert(aFeature);
+    }
+  }
+  if (!anInvalidFeatures.empty()) {
+    std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;
+    ModelAPI_Tools::findAllReferences(anInvalidFeatures, aReferences, false);
+
+    std::set<FeaturePtr>::const_iterator anIt = anInvalidFeatures.begin(),
+                                         aLast = anInvalidFeatures.end();
+    // separate features to references to parameter features and references to others
+    QStringList anInvalidFeatureNames;
+    for (; anIt != aLast; anIt++) {
+      FeaturePtr aFeature = *anIt;
+      if (aFeature.get())
+        anInvalidFeatureNames.append(aFeature->name().c_str());
+    }
+    std::string aPrefixInfo = QString("Invalid features of the sketch will be deleted: %1.\n").
+                                  arg(anInvalidFeatureNames.join(", ")).toStdString().c_str();
+    std::set<FeaturePtr> aFeatureRefsToDelete;
+    if (ModuleBase_Tools::askToDelete(anInvalidFeatures, aReferences, aConnector->desktop(),
+                                      aFeatureRefsToDelete, aPrefixInfo)) {
+      if (!aFeatureRefsToDelete.empty())
+        anInvalidFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end());
+      ModelAPI_Tools::removeFeatures(anInvalidFeatures, false);
+    }
+  }
+
   // Display sketcher objects
   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
@@ -878,18 +931,13 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
   bool aHasPlane = false;
   std::shared_ptr<GeomAPI_Pln> aPln;
-  if (aFOperation->isEditOperation()) {
-    // If it is editing of sketch then it means that plane is already defined
-    aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
-    if (aPln.get())
-      aHasPlane = true;
-  }
+  aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
   myPlaneFilter->setPlane(aPln);
 
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
-  // all sketch objects should be activated in the sketch selection modes by edit operation start
-  // in case of creation operation, there is an active widget, which activates own selection mode
-  if (aFOperation->isEditOperation() && aHasPlane)
+  // all displayed objects should be activated in current selection modes according to switched
+  // plane filter
+  if (aPln.get())
     aConnector->activateModuleSelectionModes();
 }
 
@@ -898,6 +946,7 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
   myIsMouseOverWindow = false;
   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
+  myIsConstraintsShown[PartSet_Tools::Expressions] = false;
 
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
 
@@ -958,7 +1007,6 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
   }
   // restore the module selection modes, which were changed on startSketch
   aConnector->activateModuleSelectionModes();
-  aConnector->workshop()->displayer()->activateTrihedron(false);
 }
 
 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
@@ -984,6 +1032,11 @@ void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
     qDebug("stopNestedSketch() : None");
 #endif
   }
+  /// improvement to deselect automatically all eventual selected objects, when
+  // returning to the neutral point of the Sketcher
+  // if the operation is restarted, the previous selection is used to initialize started operation
+  if (!myModule->sketchReentranceMgr()->isInternalEditStarted())
+    workshop()->selector()->clearSelection();
 }
 
 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
@@ -1023,8 +1076,12 @@ bool PartSet_SketcherMgr::operationActivatedByPreselection()
     bool aCanCommitOperation = true;
     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                             (anOperation);
-    if (aFOperation && PartSet_SketcherMgr::isDistanceOperation(aFOperation))
-      aCanCommitOperation = setDistanceValueByPreselection(anOperation, myModule->workshop());
+    if (aFOperation && PartSet_SketcherMgr::isDistanceOperation(aFOperation)) {
+      bool aValueAccepted = setDistanceValueByPreselection(anOperation, myModule->workshop(),
+                                                           aCanCommitOperation);
+      if (!aValueAccepted)
+        return isOperationStopped;
+    }
 
     if (aCanCommitOperation)
       isOperationStopped = anOperation->commit();
@@ -1081,6 +1138,11 @@ bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
     if (aFeature.get() != NULL && aFeature == activeSketch()) {
       aCanDisplay = false;
     }
+    std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+                            std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+    /// some sketch entities should be never shown, e.g. projection feature
+    if (aSketchFeature.get())
+      aCanDisplay = aSketchFeature->canBeDisplayed();
   }
   else { // there are no an active sketch
     // 2. sketch sub-features should not be visualized if the sketch operation is not active
@@ -1096,43 +1158,45 @@ bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
 
   // 3. the method should not filter the objects, which are not related to the current operation.
   // The object is filtered just if it is a current operation feature or this feature result
-  bool isObjectFound = false;
-  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                               (getCurrentOperation());
-  if (aFOperation) {
-    FeaturePtr aFeature = aFOperation->feature();
-    if (aFeature.get()) {
-      std::list<ResultPtr> aResults = aFeature->results();
-      if (theObject == aFeature)
-        isObjectFound = true;
-      else {
-        std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
-        for (; anIt != aLast && !isObjectFound; anIt++) {
-          isObjectFound = *anIt == theObject;
+  if (aCanDisplay) {
+    bool isObjectFound = false;
+    ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                                 (getCurrentOperation());
+    if (aFOperation) {
+      FeaturePtr aFeature = aFOperation->feature();
+      if (aFeature.get()) {
+        std::list<ResultPtr> aResults = aFeature->results();
+        if (theObject == aFeature)
+          isObjectFound = true;
+        else {
+          std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
+          for (; anIt != aLast && !isObjectFound; anIt++) {
+            isObjectFound = *anIt == theObject;
+          }
         }
       }
     }
-  }
-  if (isObjectFound) {
-    // 4. For created nested feature operation do not display the created feature if
-    // the mouse curstor leaves the OCC window.
-    // The correction cases, which ignores this condition:
-    // a. the property panel values modification
-    // b. the popup menu activated
-    // c. widget editor control
-    #ifndef DEBUG_DO_NOT_BY_ENTER
-    if (aCanDisplay && isNestedCreateOperation(getCurrentOperation())) {
-      ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
-      ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;
-      // the active widget editor should not influence here. The presentation should be visible always
-      // when this widget is active.
-      if (!anEditorWdg && !myIsPopupMenuActive) {
-        // during a nested create operation, the feature is redisplayed only if the mouse over view
-        // of there was a value modified in the property panel after the mouse left the view
-        aCanDisplay = canDisplayCurrentCreatedFeature();
+    if (isObjectFound) {
+      // 4. For created nested feature operation do not display the created feature if
+      // the mouse curstor leaves the OCC window.
+      // The correction cases, which ignores this condition:
+      // a. the property panel values modification
+      // b. the popup menu activated
+      // c. widget editor control
+      #ifndef DEBUG_DO_NOT_BY_ENTER
+      if (isNestedCreateOperation(getCurrentOperation())) {
+        ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
+        ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;
+        // the active widget editor should not influence here. The presentation should be visible always
+        // when this widget is active.
+        if (!anEditorWdg && !myIsPopupMenuActive) {
+          // during a nested create operation, the feature is redisplayed only if the mouse over view
+          // of there was a value modified in the property panel after the mouse left the view
+          aCanDisplay = canDisplayCurrentCreatedFeature();
+        }
       }
+      #endif
     }
-    #endif
   }
 
   // checks the sketcher constraints visibility according to active sketch check box states
@@ -1194,7 +1258,7 @@ bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature,
   return aSwitchedOn;
 }
 
-void PartSet_SketcherMgr::processHiddenObject(const std::list<ObjectPtr>& theObjects)
+/*void PartSet_SketcherMgr::processHiddenObject(const std::list<ObjectPtr>& theObjects)
 {
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                            (getCurrentOperation());
@@ -1270,7 +1334,7 @@ will be hidden: %1. Would you like to delete them?")
       }
     }
   }
-}
+}*/
 
 bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const
 {
@@ -1318,9 +1382,11 @@ void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& th
 }
 
 bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* theOperation,
-                                                         ModuleBase_IWorkshop* theWorkshop)
+                                                         ModuleBase_IWorkshop* theWorkshop,
+                                                         bool& theCanCommitOperation)
 {
   bool isValueAccepted = false;
+  theCanCommitOperation = false;
 
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                               (theOperation);
@@ -1382,6 +1448,7 @@ bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* t
             }
             anEditor->setCursorPosition(aX, anY);
             isValueAccepted = anEditor->showPopupEditor(false);
+            theCanCommitOperation = true;
           }
         }
       }
@@ -1536,6 +1603,27 @@ void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)
   }
 }
 
+void PartSet_SketcherMgr::customizePresentation(const ObjectPtr& theObject)
+{
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                                           (getCurrentOperation());
+  if (aFOperation && (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
+                      PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)))
+    SketcherPrs_Tools::sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);
+
+  // update entities selection priorities
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+  if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
+    // update priority for feature
+    updateSelectionPriority(aFeature, aFeature);
+    // update priority for results of the feature
+    std::list<ResultPtr> aResults = aFeature->results();
+    std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLastIt = aResults.end();
+    for (; anIt != aLastIt; anIt++)
+      updateSelectionPriority(*anIt, aFeature);
+  }
+}
+
 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const
 {
   return myModule->workshop()->currentOperation();
@@ -1599,7 +1687,7 @@ void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)
 
   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
   ModuleBase_ISelection* aSelect = aWorkshop->selection();
-  QList<ModuleBase_ViewerPrs> aHighlighted = aSelect->getHighlighted();
+  QList<ModuleBase_ViewerPrsPtr> aHighlighted = aSelect->getHighlighted();
 
   QList<FeaturePtr> aFeatureList;
   if (theHighlightedOnly) {
@@ -1608,7 +1696,7 @@ void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)
   else {
     fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
 
-    QList<ModuleBase_ViewerPrs> aSelected = aSelect->getSelected(ModuleBase_ISelection::AllControls);
+    QList<ModuleBase_ViewerPrsPtr> aSelected = aSelect->getSelected(ModuleBase_ISelection::AllControls);
     fillFeatureList(aSelected, myCurrentSketch, aFeatureList);
   }
 
@@ -1643,24 +1731,94 @@ void PartSet_SketcherMgr::restoreSelection()
 void PartSet_SketcherMgr::onShowConstraintsToggle(int theType, bool theState)
 {
   PartSet_Tools::ConstraintVisibleState aType = (PartSet_Tools::ConstraintVisibleState)theType;
-  if (myIsConstraintsShown.contains(aType) && myIsConstraintsShown[aType] == theState)
-    return;
+
+  updateBySketchParameters(aType, theState);
+}
+
+void PartSet_SketcherMgr::updateBySketchParameters(
+                                   const PartSet_Tools::ConstraintVisibleState& theType,
+                                   bool theState)
+{
   if (myCurrentSketch.get() == NULL)
     return;
 
-  myIsConstraintsShown[aType] = theState;
+  bool aPrevState = myIsConstraintsShown[theType];
+  myIsConstraintsShown[theType] = theState;
+
+  switch (theType) {
+    case PartSet_Tools::Geometrical:
+    case PartSet_Tools::Dimensional: {
+      if (aPrevState != theState) {
+        ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
+        XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
+        for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
+          FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);
+          bool aProcessed = false;
+          bool aConstraintDisplayed = canDisplayConstraint(aSubFeature, theType, aProcessed);
+          if (aProcessed)
+            aSubFeature->setDisplayed(aConstraintDisplayed);
+        }
+        Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+      }
+    }
+    break;
+    case PartSet_Tools::Expressions: {
+      if (aPrevState != theState) {
+        /// call all sketch features redisplay, the expression state will be corrected in customize
+        /// of distance presentation
+        Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+        PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);
+      }
+    }
+    break;
+  }
+}
 
-  ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
-  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
+void PartSet_SketcherMgr::updateSelectionPriority(ObjectPtr theObject,
+                                                  FeaturePtr theFeature)
+{
+  if (!theObject.get() || !theFeature.get())
+    return;
 
-  for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
-    FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);
-    bool aProcessed = false;
-    bool aConstraintDisplayed = canDisplayConstraint(aSubFeature, aType, aProcessed);
-    if (aProcessed)
-      aSubFeature->setDisplayed(aConstraintDisplayed);
+  AISObjectPtr anAIS = workshop()->displayer()->getAISObject(theObject);
+  Handle(AIS_InteractiveObject) anAISIO;
+  if (anAIS.get() != NULL) {
+    anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
+  }
+
+  if (!anAISIO.IsNull()) { // the presentation for the object is visualized
+    int anAdditionalPriority = 0;
+    // current feature
+    std::shared_ptr<SketchPlugin_Feature> aSPFeature =
+            std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
+    if (aSPFeature.get() != NULL) {
+      // 1. Vertices
+      // 2. Simple segments
+      // 3. External objects (violet color)
+      // 4. Auxiliary segments (dotted)
+      // StdSelect_BRepSelectionTool::Load uses priority calculating:
+      // Standard_Integer aPriority = (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority;
+      // Priority of Vertex is 8, edge(segment) is 7.
+      // It might be not corrected as provides the condition above.
+      bool isExternal = aSPFeature->isExternal();
+      bool isAuxiliary = PartSet_Tools::isAuxiliarySketchEntity(aSPFeature);
+      // current feature
+      if (!isExternal && !isAuxiliary)
+        anAdditionalPriority = 30;
+      // external feature
+      if (isExternal)
+        anAdditionalPriority = 20;
+      // auxiliary feature
+      if (isAuxiliary) {
+        anAdditionalPriority = 10; /// auxiliary objects should have less priority that
+        // edges/vertices of local selection on not-sketch objects
+      }
+      Handle(ModuleBase_ResultPrs) aResult = Handle(ModuleBase_ResultPrs)::DownCast(anAISIO);
+      if (!aResult.IsNull()) {
+        aResult->setAdditionalSelectionPriority(anAdditionalPriority);
+      }
+    }
   }
-  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
 }
 
 XGUI_Workshop* PartSet_SketcherMgr::workshop() const