Salome HOME
Merge branch 'master' into occ/bsplines
[modules/shaper.git] / src / PartSet / PartSet_WidgetBSplinePoints.cpp
1 // Copyright (C) 2019-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <PartSet_WidgetBSplinePoints.h>
21
22 #include <PartSet_CenterPrs.h>
23 #include <PartSet_ExternalObjectsMgr.h>
24 #include <PartSet_Module.h>
25 #include <PartSet_SketcherReentrantMgr.h>
26 #include <PartSet_WidgetPoint2d.h>
27
28 #include <XGUI_Tools.h>
29 #include <XGUI_Workshop.h>
30 #include <XGUI_Displayer.h>
31
32 #include <ModuleBase_ISelection.h>
33 #include <ModuleBase_IViewer.h>
34 #include <ModuleBase_IViewWindow.h>
35 #include <ModuleBase_LabelValue.h>
36 #include <ModuleBase_Tools.h>
37 #include <ModuleBase_ViewerPrs.h>
38 #include <ModuleBase_WidgetValidator.h>
39 #include <ModuleBase_WidgetValidated.h>
40
41 #include <Config_Keywords.h>
42 #include <Config_WidgetAPI.h>
43
44 #include <Events_Loop.h>
45
46 #include <ModelAPI_Events.h>
47 #include <ModelAPI_AttributeDoubleArray.h>
48 #include <ModelAPI_AttributeRefAttrList.h>
49 #include <ModelAPI_CompositeFeature.h>
50
51 #include <GeomDataAPI_Point2D.h>
52 #include <GeomDataAPI_Point2DArray.h>
53
54 #include <GeomAPI_Pnt2d.h>
55 #include <GeomAPI_IPresentable.h>
56
57 #include <SketchPlugin_Feature.h>
58
59 #include <QGridLayout>
60 #include <QGroupBox>
61 #include <QMouseEvent>
62 #include <QGraphicsEffect>
63 #include <QScrollArea>
64
65 static const double MaxCoordinate = 1e12;
66
67 static bool IsPointCreated = false;
68
69
70 PartSet_WidgetBSplinePoints::PartSet_WidgetBSplinePoints(QWidget* theParent,
71                                              ModuleBase_IWorkshop* theWorkshop,
72                                              const Config_WidgetAPI* theData)
73 : ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop),
74   myValueIsCashed(false), myIsFeatureVisibleInCash(true),
75   myXValueInCash(0), myYValueInCash(0),
76   myPointIndex(0), myFinished(false)
77 {
78   myRefAttribute = theData->getProperty("reference_attribute");
79   QVBoxLayout* aMainLayout = new QVBoxLayout(this);
80   ModuleBase_Tools::zeroMargins(aMainLayout);
81
82   // the control should accept the focus, so the boolean flag is corrected to be true
83   myIsObligatory = true;
84   QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
85   myBox = new QGroupBox(aPageName, theParent);
86   myBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
87   myBox->setFlat(false);
88   aMainLayout->addWidget(myBox);
89
90   bool aAcceptVariables = theData->getBooleanAttribute(DOUBLE_WDG_ACCEPT_EXPRESSIONS, true);
91
92   // B-spline weights attribute
93   myWeightsAttr = theData->getProperty("weights");
94
95   QVBoxLayout* aLayout = new QVBoxLayout(myBox);
96   ModuleBase_Tools::adjustMargins(aLayout);
97
98   myScrollArea = new QScrollArea(myBox);
99   myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
100   myScrollArea->setWidgetResizable(true);
101   myScrollArea->setFrameStyle(QFrame::NoFrame);
102   aLayout->addWidget(myScrollArea);
103
104   QWidget* aContainer = new QWidget(myScrollArea);
105   QVBoxLayout* aBoxLay = new QVBoxLayout(aContainer);
106   aBoxLay->setContentsMargins(0, 0, 0, 0);
107
108   myGroupBox = new QWidget(aContainer);
109   QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
110   ModuleBase_Tools::adjustMargins(aGroupLay);
111   aGroupLay->setSpacing(4);
112   aGroupLay->setColumnStretch(1, 1);
113   createNextPoint();
114   aBoxLay->addWidget(myGroupBox);
115   aBoxLay->addStretch(1);
116
117   myScrollArea->setWidget(aContainer);
118
119   myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
120   myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
121                                          theData->getProperty("can_create_external"), true);
122 }
123
124 void PartSet_WidgetBSplinePoints::createNextPoint()
125 {
126   storeCurentValue();
127
128   QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
129   int row = (int)myXSpin.size();
130
131   QString aPoleStr = tr("Pole %1");
132   aPoleStr = aPoleStr.arg(myXSpin.size() + 1);
133
134   QGroupBox* aPoleGroupBox = new QGroupBox(aPoleStr, myGroupBox);
135   QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
136   ModuleBase_Tools::adjustMargins(aPoleLay);
137   aPoleLay->setSpacing(2);
138   aPoleLay->setColumnStretch(1, 1);
139
140   myXSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("X")));
141   aPoleLay->addWidget(myXSpin.back(), 0, 1);
142   myYSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("Y")));
143   aPoleLay->addWidget(myYSpin.back(), 1, 1);
144
145   aGroupLay->addWidget(aPoleGroupBox, row, 1);
146   IsPointCreated = true;
147 }
148
149 void PartSet_WidgetBSplinePoints::removeLastPoint()
150 {
151   QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
152   QWidget* aXSpin = myXSpin.back();
153   QWidget* aYSpin = myYSpin.back();
154   QWidget* aBox = myXSpin.back()->parentWidget();
155   myYSpin.pop_back();
156   myXSpin.pop_back();
157
158   aGroupLay->removeWidget(aXSpin);
159   aGroupLay->removeWidget(aYSpin);
160   aGroupLay->removeWidget(aBox);
161
162   aBox->deleteLater();
163
164   // update B-spline feature attributes
165   storeValueCustom();
166 }
167
168 bool PartSet_WidgetBSplinePoints::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
169 {
170   bool aValid = true;
171
172   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
173   if (aModule->sketchReentranceMgr()->isInternalEditActive())
174     return true; // when internal edit is started a new feature is created. I has not results, AIS
175
176   // the selection is not possible if the current feature has no presentation for the current
177   // attribute not in AIS not in results. If so, no object in current feature where make
178   // coincidence, so selection is not necessary
179   GeomShapePtr anAISShape;
180   GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(myFeature);
181   if (aPrs.get()) {
182     AISObjectPtr anAIS;
183     anAIS = aPrs->getAISObject(anAIS);
184     if (anAIS.get()) {
185       anAISShape = anAIS->getShape();
186     }
187   }
188   const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = myFeature->results();
189   if (!anAISShape.get() && aResults.empty())
190     return true;
191
192   AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
193   if (aRefAttrList)
194     return isValidSelectionForAttribute_(theValue, myFeature->attribute(attributeID()));
195   return true;
196 }
197
198 bool PartSet_WidgetBSplinePoints::isValidSelectionForAttribute_(
199                                             const ModuleBase_ViewerPrsPtr& theValue,
200                                             const AttributePtr& theAttribute)
201 {
202   bool aValid = false;
203
204   // stores the current values of the widget attribute
205   bool isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked;
206
207   AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
208   ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, true,
209       isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
210   myWidgetValidator->storeAttributeValue(aRefAttrList);
211
212   // saves the owner value to the widget attribute
213   aValid = setSelectionCustom(theValue);
214   if (aValid)
215     // checks the attribute validity
216     aValid = myWidgetValidator->isValidAttribute(theAttribute);
217
218   // restores the current values of the widget attribute
219   myWidgetValidator->restoreAttributeValue(aRefAttrList, aValid);
220   myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
221
222   ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, false,
223       isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
224   return aValid;
225 }
226
227 bool PartSet_WidgetBSplinePoints::setSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
228 {
229   bool isDone = false;
230   GeomShapePtr aShape = theValue->shape();
231   if (aShape.get() && !aShape->isNull()) {
232     Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
233     const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
234     GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
235     if (aPnt) {
236       fillRefAttribute(aPnt, theValue);
237       isDone = true;
238     }
239     else if (aTDShape.ShapeType() == TopAbs_EDGE) {
240       fillRefAttribute(theValue);
241       isDone = true;
242     }
243   }
244   return isDone;
245 }
246
247 static void fillLabels(std::vector<ModuleBase_LabelValue*>& theLabels, const double theValue)
248 {
249   for (std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
250        anIt != theLabels.end(); ++anIt)
251     (*anIt)->setValue(theValue);
252 }
253
254 bool PartSet_WidgetBSplinePoints::resetCustom()
255 {
256   bool aDone = false;
257   if (!isUseReset() || isComputedDefault())
258     aDone = false;
259   else {
260     if (myValueIsCashed) {
261       // if the restored value should be hidden, aDone = true to set
262       // reset state for the widget in the parent
263       aDone = restoreCurentValue();
264       emit objectUpdated();
265     }
266     else {
267       // it is important to block the spin box control in order to do not through out the
268       // locking of the validating state.
269       fillLabels(myXSpin, 0.0);
270       fillLabels(myYSpin, 0.0);
271
272       storeValueCustom();
273       aDone = true;
274     }
275   }
276   return aDone;
277 }
278
279 PartSet_WidgetBSplinePoints::~PartSet_WidgetBSplinePoints()
280 {
281   delete myExternalObjectMgr;
282 }
283
284 bool PartSet_WidgetBSplinePoints::setPoint(double theX, double theY)
285 {
286   if (fabs(theX) >= MaxCoordinate || fabs(theY) >= MaxCoordinate)
287     return false;
288
289   myXSpin.back()->setValue(theX);
290   myYSpin.back()->setValue(theY);
291
292   storeValue();
293   return true;
294 }
295
296 void PartSet_WidgetBSplinePoints::storePolesAndWeights() const
297 {
298   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
299   AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
300       aData->attribute(attributeID()));
301   AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
302
303   int aSize = (int)myXSpin.size();
304   aPointArray->setSize(aSize);
305   aWeightsArray->setSize(aSize);
306
307   std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
308   std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
309   for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end(); ++anIndex, ++aXIt, ++aYIt)
310     aPointArray->setPnt(anIndex, (*aXIt)->value(), (*aYIt)->value());
311
312   double aWeight = Config_PropManager::real(SKETCH_TAB_NAME, "spline_weight");
313   for (int anIndex = 0; anIndex < aSize; ++anIndex)
314     aWeightsArray->setValue(anIndex, aWeight);
315 }
316
317 bool PartSet_WidgetBSplinePoints::storeValueCustom()
318 {
319   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
320   if (!aData || !aData->isValid()) // can be on abort of sketcher element
321     return false;
322   AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
323       aData->attribute(attributeID()));
324   AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
325
326   PartSet_WidgetBSplinePoints* that = (PartSet_WidgetBSplinePoints*) this;
327   bool isBlocked = that->blockSignals(true);
328   bool isImmutable = aPointArray->setImmutable(true);
329
330   if (myFeature->isMacro()) {
331     // Moving points of macro-features has been processed directly (without solver)
332     storePolesAndWeights();
333     updateObject(myFeature);
334
335   } else {
336     if (!aPointArray->isInitialized()) {
337       storePolesAndWeights();
338     }
339
340     std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
341         new ModelAPI_ObjectMovedMessage(this));
342     aMessage->setMovedAttribute(aPointArray, aPointArray->size() - 1);
343     aMessage->setOriginalPosition(aPointArray->pnt(aPointArray->size() - 1));
344     aMessage->setCurrentPosition(myXSpin.back()->value(), myYSpin.back()->value());
345     Events_Loop::loop()->send(aMessage);
346   }
347
348   aPointArray->setImmutable(isImmutable);
349   that->blockSignals(isBlocked);
350
351   return true;
352 }
353
354 bool PartSet_WidgetBSplinePoints::restoreValueCustom()
355 {
356   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
357   AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
358       aData->attribute(attributeID()));
359   AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
360
361   if (aPointArray->isInitialized()) {
362     while (myXSpin.size() < aPointArray->size())
363       createNextPoint();
364
365     std::vector<ModuleBase_LabelValue*>::iterator aXIt = myXSpin.begin();
366     std::vector<ModuleBase_LabelValue*>::iterator aYIt = myYSpin.begin();
367     for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end();
368          ++anIndex, ++aXIt, ++aYIt) {
369       GeomPnt2dPtr aPoint = aPointArray->pnt(anIndex);
370       (*aXIt)->setValue(aPoint->x());
371       (*aYIt)->setValue(aPoint->y());
372     }
373   }
374   else {
375     if (myXSpin.empty())
376       createNextPoint();
377
378     myXSpin.back()->setValue(0.0);
379     myYSpin.back()->setValue(0.0);
380   }
381
382   return true;
383 }
384
385 static void storeArray(const std::vector<ModuleBase_LabelValue*>& theLabels,
386                        std::vector<double>& theValues)
387 {
388   theValues.clear();
389   theValues.reserve(theLabels.size());
390   for (std::vector<ModuleBase_LabelValue*>::const_iterator anIt = theLabels.begin();
391        anIt != theLabels.end(); ++anIt)
392     theValues.push_back((*anIt)->value());
393 }
394
395 void PartSet_WidgetBSplinePoints::storeCurentValue()
396 {
397   myValueIsCashed = true;
398   myIsFeatureVisibleInCash = XGUI_Displayer::isVisible(
399                        XGUI_Tools::workshop(myWorkshop)->displayer(), myFeature);
400
401   storeArray(myXSpin, myXValueInCash);
402   storeArray(myYSpin, myYValueInCash);
403 }
404
405 static void restoreArray(std::vector<double>& theCacheValues,
406                          std::vector<ModuleBase_LabelValue*>& theLabels)
407 {
408   std::vector<double>::iterator aCIt = theCacheValues.begin();
409   std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
410   for (; anIt != theLabels.end(); ++anIt) {
411     if (aCIt != theCacheValues.end())
412       (*anIt)->setValue(*aCIt++);
413     else
414       (*anIt)->setValue(0.0);
415   }
416   theCacheValues.clear();
417 }
418
419 bool PartSet_WidgetBSplinePoints::restoreCurentValue()
420 {
421   bool aRestoredAndHidden = true;
422
423   bool isVisible = myIsFeatureVisibleInCash;
424
425   myValueIsCashed = false;
426   myIsFeatureVisibleInCash = true;
427   // fill the control widgets by the cashed value
428   restoreArray(myXValueInCash, myXSpin);
429   restoreArray(myYValueInCash, myYSpin);
430
431   // store value to the model
432   storeValueCustom();
433   if (isVisible) {
434     setValueState(Stored);
435     aRestoredAndHidden = false;
436   }
437   else
438     aRestoredAndHidden = true;
439
440   return aRestoredAndHidden;
441 }
442
443 QList<QWidget*> PartSet_WidgetBSplinePoints::getControls() const
444 {
445   QList<QWidget*> aControls;
446   aControls.append(myScrollArea);
447   return aControls;
448 }
449
450 void PartSet_WidgetBSplinePoints::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
451 {
452   theModuleSelectionModes = -1;
453   theModes << TopAbs_VERTEX;
454   theModes << TopAbs_EDGE;
455 }
456
457 void PartSet_WidgetBSplinePoints::deactivate()
458 {
459   // the value of the control should be stored to model if it was not
460   // initialized yet. It is important when we leave this control by Tab key.
461   // It should not be performed by the widget activation as the preview
462   // is visualized with default value. Line point is moved to origin.
463   AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
464   if (anAttribute && !anAttribute->isInitialized())
465     storeValue();
466
467   ModuleBase_ModelWidget::deactivate();
468 }
469
470 void PartSet_WidgetBSplinePoints::mouseReleased(ModuleBase_IViewWindow* theWindow,
471                                                 QMouseEvent* theEvent)
472 {
473   // the contex menu release by the right button should not be processed by this widget
474   if (theEvent->button() != Qt::LeftButton)
475     return;
476
477   ModuleBase_ISelection* aSelection = myWorkshop->selection();
478   Handle(V3d_View) aView = theWindow->v3dView();
479
480   QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
481   ModuleBase_ViewerPrsPtr aFirstValue =
482     aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
483   if (!aFirstValue.get() && myPreSelected.get()) {
484     aFirstValue = myPreSelected;
485   }
486
487   TopoDS_Shape aSelectedShape;
488   ObjectPtr aSelectedObject;
489
490   // if we have selection and use it
491   if (aFirstValue.get() && isValidSelectionCustom(aFirstValue) &&
492       aFirstValue->shape().get()) { // Trihedron Axis may be selected, but shape is empty
493     GeomShapePtr aGeomShape = aFirstValue->shape();
494     aSelectedShape = aGeomShape->impl<TopoDS_Shape>();
495     aSelectedObject = aFirstValue->object();
496
497     FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aSelectedObject);
498     std::shared_ptr<SketchPlugin_Feature> aSPFeature;
499     if (aSelectedFeature.get())
500       aSPFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
501
502     bool isSketchExternalFeature = aSPFeature.get() && aSPFeature->isExternal();
503     if ((!aSPFeature && !aSelectedShape.IsNull()) || isSketchExternalFeature) {
504       ObjectPtr aFixedObject =
505           PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aSelectedObject, mySketch);
506       if (aFixedObject)
507         aSelectedObject = aFixedObject;
508       else if (!isSketchExternalFeature) {
509         FeaturePtr aCreatedFeature;
510         aSelectedObject = PartSet_Tools::createFixedObjectByExternal(
511             aGeomShape, aSelectedObject, mySketch, false, aCreatedFeature);
512       }
513     }
514   }
515   // The selection could be a center of an external circular object
516   else if (aFirstValue.get() && (!aFirstValue->interactive().IsNull())) {
517     Handle(PartSet_CenterPrs) aAIS =
518         Handle(PartSet_CenterPrs)::DownCast(aFirstValue->interactive());
519     if (!aAIS.IsNull()) {
520       gp_Pnt aPntComp = aAIS->Component()->Pnt();
521       GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
522       aSelectedShape = aVertPtr->impl<TopoDS_Shape>();
523
524       aSelectedObject =
525           PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aAIS->object(), mySketch);
526       if (!aSelectedObject.get())
527       {
528         FeaturePtr aCreatedFeature;
529         aSelectedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
530             aAIS->centerType(), mySketch, false, aCreatedFeature);
531       }
532     }
533   }
534
535   GeomPnt2dPtr aSelectedPoint = PartSet_Tools::getPnt2d(aView, aSelectedShape, mySketch);
536   if (!aSelectedPoint) {
537     aSelectedPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
538     setValueState(Stored); // in case of edge selection, Apply state should also be updated
539   }
540   if (aSelectedObject)
541     fillRefAttribute(aSelectedObject);
542   else
543     fillRefAttribute(aSelectedPoint, aFirstValue);
544
545   // next pole of B-spline
546   createNextPoint();
547 }
548
549 void PartSet_WidgetBSplinePoints::mouseMoved(ModuleBase_IViewWindow* theWindow,
550                                              QMouseEvent* theEvent)
551 {
552   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
553
554   if (myFinished || isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditActive())
555     return;
556
557   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
558
559   double aX = 0, aY = 0;
560   PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, aY);
561   if (myState != ModifiedInViewer)
562     storeCurentValue();
563   // we need to block the value state change
564   bool isBlocked = blockValueState(true);
565   setPoint(aX, aY);
566   blockValueState(isBlocked);
567   setValueState(ModifiedInViewer);
568
569   if (IsPointCreated) {
570     QPoint aPnt = myGroupBox->geometry().bottomLeft();
571     myScrollArea->ensureVisible(aPnt.x(), aPnt.y());
572     IsPointCreated = false;
573   }
574 }
575
576 bool PartSet_WidgetBSplinePoints::processEscape()
577 {
578   bool isProcessed = !isEditingMode();
579   if (isProcessed) {
580     // remove widgets corrsponding to the last pole/weight of B-spline
581     removeLastPoint();
582     myFinished = true;
583
584     emit focusOutWidget(this);
585   }
586   return isProcessed;
587 }
588
589 bool PartSet_WidgetBSplinePoints::useSelectedShapes() const
590 {
591   return true;
592 }
593
594 AttributeRefAttrListPtr PartSet_WidgetBSplinePoints::attributeRefAttrList() const
595 {
596   if (myRefAttribute.empty())
597     return AttributeRefAttrListPtr();
598
599   AttributePtr anAttributeRef = feature()->attribute(myRefAttribute);
600   if (!anAttributeRef.get())
601     return AttributeRefAttrListPtr();
602
603   return std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(anAttributeRef);
604 }
605
606 void PartSet_WidgetBSplinePoints::fillRefAttribute(GeomPnt2dPtr theClickedPoint,
607                               const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
608 {
609   AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
610   if (!aRefAttrList.get())
611     return;
612
613   FeaturePtr aFeature = feature();
614   std::string anAttribute = attributeID();
615
616   if (aFeature.get()) {
617     AttributePoint2DPtr aClickedFeaturePoint =
618         PartSet_WidgetPoint2D::findFirstEqualPointInSketch(mySketch, aFeature, theClickedPoint);
619     if (aClickedFeaturePoint.get())
620       aRefAttrList->append(aClickedFeaturePoint);
621     else
622       fillRefAttribute(theValue);
623   }
624 }
625
626 void PartSet_WidgetBSplinePoints::fillRefAttribute(const ModuleBase_ViewerPrsPtr& theValue)
627 {
628   ObjectPtr anObject;
629   if (theValue)
630     anObject = getGeomSelection(theValue);
631   fillRefAttribute(anObject);
632 }
633
634 void PartSet_WidgetBSplinePoints::fillRefAttribute(const ObjectPtr& theObject)
635 {
636   AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
637   if (aRefAttrList.get())
638     aRefAttrList->append(theObject);
639 }
640
641 ObjectPtr PartSet_WidgetBSplinePoints::getGeomSelection(const ModuleBase_ViewerPrsPtr& theValue)
642 {
643   ObjectPtr anObject;
644   GeomShapePtr aShape;
645   ModuleBase_ISelection* aSelection = myWorkshop->selection();
646   anObject = aSelection->getResult(theValue);
647   aShape = aSelection->getShape(theValue);
648   myExternalObjectMgr->getGeomSelection(theValue, anObject, aShape, myWorkshop, sketch(), true);
649
650   return anObject;
651 }